Skip to content

Commit

Permalink
Prettify, remove .format in favor of f-strings.
Browse files Browse the repository at this point in the history
  • Loading branch information
migueLib committed Nov 6, 2024
1 parent 6849284 commit 5ab2d30
Show file tree
Hide file tree
Showing 9 changed files with 572 additions and 375 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
# Staging module for Miltenyi - MACSIMA to MCMICRO


## Docker implementation

TODO: Add instructions on how to run the tool from Docker

## CLI

TODO: Add instructions on how to run the CLI
10 changes: 6 additions & 4 deletions macsima2mc/CLI.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import argparse
import pathlib



#---CLI-BLOCK---#
def get_args():
def get_args():
"""
This function parses the command line arguments and returns them as a namespace object.
returns: namespace object with the arguments.
"""
parser=argparse.ArgumentParser()

#Mandatory arguments

parser.add_argument('-i',
'--input',
required=True,
Expand Down
49 changes: 40 additions & 9 deletions macsima2mc/illumination_corr.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,55 @@
from basicpy import BaSiC
import numpy as np

def indices_per_channel(total_imgs,no_of_channels):
def indices_per_channel(total_imgs, no_of_channels):
"""
This function creates a list of lists with the indices of the images in the stack per channel.
Args:
total_imgs (int): total number of images in the stack.
no_of_channels (int): number of channels.
Returns:
list: list of lists with the indices of the images in the stack per channel.
"""

#total_imgs in the stack
img_indices=[ list( range(ch,total_imgs,no_of_channels) ) for ch in range( 0, no_of_channels ) ]
img_indices = [list(range(ch,total_imgs,no_of_channels)) for ch in range(0, no_of_channels)]
return img_indices


def extract_channel_imgs (stack,indices):
"""
This function extracts the images in the stack per channel.
Args:
stack (np.array): stack of images.
indices (list): list of indices of the images in the stack per channel.
Returns:
np.array: stack of images per channel.
"""

return stack[indices,:,:]


def apply_corr(uncorr_stack,no_of_channels):
corr_stack=np.zeros( uncorr_stack.shape,dtype=uncorr_stack.dtype )
total_imgs=uncorr_stack.shape[0]
indices=indices_per_channel(total_imgs, no_of_channels)
basic = BaSiC(get_darkfield=False, smoothness_flatfield=1.0,fitting_mode = "approximate", sort_intensity = True)
"""
This function applies the BaSiC algorithm to correct the illumination in the images.
Args:
uncorr_stack (np.array): stack of uncorrected images.
no_of_channels (int): number of channels.
Returns:
np.array: stack of corrected images.
"""

corr_stack = np.zeros( uncorr_stack.shape,dtype=uncorr_stack.dtype )
total_imgs = uncorr_stack.shape[0]
indices = indices_per_channel(total_imgs, no_of_channels)
basic = BaSiC(get_darkfield=False, smoothness_flatfield=1.0, fitting_mode="approximate", sort_intensity=True)

for ind_list in indices:
uncorr_imgs=extract_channel_imgs(uncorr_stack, ind_list)
uncorr_imgs = extract_channel_imgs(uncorr_stack, ind_list)
basic.fit(uncorr_imgs)
ffp=basic.flatfield
corr_stack[ind_list,:,:]=np.uint16( np.clip( uncorr_imgs.astype(float)/ffp ,0, 65535) )
ffp = basic.flatfield
corr_stack[ind_list,:,:] = np.uint16(np.clip(uncorr_imgs.astype(float) / ffp, 0, 65535))

return corr_stack


51 changes: 26 additions & 25 deletions macsima2mc/macsima2mc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,37 @@
import CLI
import mc_tools



#input_test_folder=Path("D:/macsima_data_samples/macsima_data_v2/8_Cycle2")
#output_test_folder=Path('D:/test_folder')

def main(args):
input=args.input
output=args.output
ref=args.reference_marker
basicpy_corr=args.illumination_correction
out_folder_name=args.output_dir

cycle_info=tools.cycle_info( input , macsima_pattern(version=2),ref_marker= ref)
cycle_info=tools.append_metadata( cycle_info )
#cycle_info.to_csv( args.output / 'cycle_{c}_info.csv'.format(c=f'{6:03d}'), index=False )
output_dirs=tools.create_stack( cycle_info, output ,
ref_marker=ref,
hi_exp=args.hi_exposure_only,
ill_corr=basicpy_corr,
out_folder=out_folder_name
)
[mc_tools.write_markers_file(path) for path in output_dirs]


if __name__ == '__main__':
def main():
# Get arguments
args = CLI.get_args()
main(args)



# Assign arguments to variables
input = args.input
output = args.output
ref = args.reference_marker
basicpy_corr = args.illumination_correction
out_folder_name = args.output_dir

# Get cycle info
cycle_info = tools.cycle_info(input, macsima_pattern(version=2), ref_marker= ref)

# Create stack
cycle_info = tools.append_metadata( cycle_info )
#cycle_info.to_csv( args.output / 'cycle_{c}_info.csv'.format(c=f'{6:03d}'), index=False )
output_dirs = tools.create_stack(cycle_info,
output,
ref_marker=ref,
hi_exp=args.hi_exposure_only,
ill_corr=basicpy_corr,
out_folder=out_folder_name)

# Save markers file in each output directory
for path in output_dirs:
mc_tools.write_markers_file(path)


if __name__ == '__main__':
main()
163 changes: 85 additions & 78 deletions macsima2mc/mc_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,90 +8,97 @@


def flatten_list(lol):
#lol=list of lists
return [x for xs in lol
for x in xs
]
"""
This function flattens a list of lists.
Args:
lol (list): list of lists.
Returns:
list: flattened list.
"""
return [x for xs in lol for x in xs]


def markers_file():

columns={'channel_number': [] ,
'cycle_number': [],
'marker_name':[],
'Filter':[],
'background':[],
'exposure':[],
'remove':[]
}

return columns
"""
This function creates a dictionary with the columns of the markers.csv file.
Returns:
dict: dictionary with the columns of the markers.csv file.
"""
columns = {'channel_number': [],
'cycle_number': [],
'marker_name':[],
'Filter':[],
'background':[],
'exposure':[],
'remove':[]
}

return columns

def get_patterns():
#Dictionary of tuples where first element indicates the pattern to search and
#second element is a boolean that indicates whether to transform the search output into a value or not
#the keys of this dictionary should be a subset of the keys in the markers_file function.

patterns={
'cycle_number':(r"cycle-(.*?)-", True),
'marker_name': (r"markers-(.*?)-",False),
'Filter':(r"-filters-(.*?).ome",False),
'background':(r"-src-(.*?)-" ,False)
}
def get_patterns():
"""
Dictionary of tuples where first element indicates the pattern to search and
second element is a boolean that indicates whether to transform the search output into a value or not
the keys of this dictionary should be a subset of the keys in the markers_file function.
Returns:
dict: dictionary with regular expressions to extract metadata from macsima filenames.
"""

return patterns
patterns = {
'cycle_number': (r"cycle-(.*?)-", True),
'marker_name' : (r"markers-(.*?)-",False),
'Filter' : (r"-filters-(.*?).ome",False),
'background' : (r"-src-(.*?)-" ,False)
}

#input=Path('D:/test_folder/rack-01-well-B01-roi-001-exp-1/raw')
#img_names=[ file.stem for file in list( input.glob('*.tif*') ) ]
return patterns

#file[ ]=flatten_list( [ m.split('__') for m in extract_values( tup[0] , file_names,number_cast=tup[1] )] )
#file[key]=flatten_list( [ m.split('__') for m in extract_values( tup[0] , file_names,number_cast=tup[1] )] )

def write_markers_file( data_path, ref_marker='DAPI'):
img_paths=list( sorted( data_path.glob('*.tif*') ) )
mks_file=markers_file()
patt=get_patterns()

for img in img_paths:
img_name=[img.stem]

cycle_no= extract_values( patt['cycle_number'][0] , img_name, number_cast=patt['cycle_number'][1] )
background= extract_values( patt['background'][0] , img_name, number_cast=patt['background'][1] )

markers= extract_values( patt['marker_name'][0] , img_name ,number_cast=patt['marker_name'][1] )[0].split('__')
filters= extract_values( patt['Filter'][0] , img_name ,number_cast=patt['Filter'][1] )[0].split('__')
ome= from_tiff(img)





if background[0]=='B':
remove=len(markers)*['TRUE']
markers=['bg_{c}_{m}-{f}'.format( c= f'{cycle_no[0]:03d}' , m=x , f=y ) for x,y in zip(markers,filters) ]
fmt_background=len(markers)*['']
else:
fmt_background=[]
remove=len(markers)*['']
for x,y in zip(markers,filters):
if x==ref_marker:
fmt_background.append( '' )
else:
fmt_background.append( 'bg_{c}_{m}-{f}'.format( c=f'{cycle_no[0]:03d}', m=x , f=y ) )

#fmt_background=[ 'bg_{c}_{m}-{f}'.format( c=f'{cycle_no[0]:03d}' , m=x , f=y ) for x,y in zip(markers,filters) ]


mks_file['cycle_number'].extend( len(markers)*cycle_no )
mks_file['marker_name'].extend( markers )
mks_file['Filter'].extend( filters )
mks_file['background'].extend( fmt_background )
mks_file['exposure'].extend( [ome.images[0].pixels.planes[ch].exposure_time for ch,_ in enumerate(markers) ] )
mks_file['remove'].extend( remove )

mks_file['channel_number']=list( range( 1, 1 + len(mks_file['marker_name']) ) )
mks_file_df=DataFrame(mks_file)
mks_file_df.to_csv( data_path.parent.absolute() / 'markers.csv' , index=False )
return mks_file



"""
This function writes the markers.csv file.
Args:
data_path (Path): path to the folder containing the images.
ref_marker (str): reference marker.
Returns:
dict: dictionary with the columns of the markers.csv file.
"""

img_paths = list(sorted( data_path.glob('*.tif*')))
mks_file = markers_file()
patt = get_patterns()

for img in img_paths:
img_name = [img.stem]
cycle_no = extract_values(patt['cycle_number'][0], img_name, number_cast=patt['cycle_number'][1])
background = extract_values(patt['background'][0], img_name, number_cast=patt['background'][1])
markers = extract_values(patt['marker_name'][0], img_name, number_cast=patt['marker_name'][1])[0].split('__')
filters = extract_values(patt['Filter'][0], img_name, number_cast=patt['Filter'][1])[0].split('__')
ome = from_tiff(img)

if background[0]=='B':
remove = len(markers)*['TRUE']
markers = ['bg_{c}_{m}-{f}'.format( c= f'{cycle_no[0]:03d}' , m=x , f=y ) for x,y in zip(markers,filters) ]
fmt_background = len(markers)*['']
else:
fmt_background = []
remove = len(markers)*['']
for x,y in zip(markers,filters):
if x == ref_marker:
fmt_background.append('')
else:
fmt_background.append(f'bg_{cycle_no[0]:03d}_{x}-{y}')

mks_file['cycle_number'].extend(len(markers)*cycle_no)
mks_file['marker_name'].extend(markers)
mks_file['Filter'].extend(filters)
mks_file['background'].extend(fmt_background)
mks_file['exposure'].extend([ome.images[0].pixels.planes[ch].exposure_time for ch,_ in enumerate(markers)])
mks_file['remove'].extend(remove)

mks_file['channel_number'] = list(range(1, 1 + len(mks_file['marker_name'])))
mks_file_df = DataFrame(mks_file)
mks_file_df.to_csv( data_path.parent.absolute() / 'markers.csv' , index=False )

return mks_file
Loading

0 comments on commit 5ab2d30

Please sign in to comment.