Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ROI name prefix to tiled region FOV names #66

Merged
merged 3 commits into from
Mar 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions toffy/settings.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# tiled regions
REGION_PARAM_FIELDS = ['region_start_row', 'region_start_col', 'fov_num_row', 'fov_num_col',
'row_fov_size', 'col_fov_size', 'region_rand']
REGION_PARAM_FIELDS = ['region_name', 'region_start_row', 'region_start_col',
'fov_num_row', 'fov_num_col', 'row_fov_size', 'col_fov_size', 'region_rand']

# mibitracker
MIBITRACKER_BACKEND = 'https://backend-dot-mibitracker-angelolab.appspot.com'
Expand Down
12 changes: 8 additions & 4 deletions toffy/tiling_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,11 @@ def read_tiled_region_inputs(region_corners, region_params):
A `dict` mapping each region-specific parameter to a list of values per FOV
"""

# read in the data for each fov (region_start from region_corners_path, all others from user)
# read in the data for each region (region_start from region_corners_path, others from user)
for fov in region_corners['fovs']:
# append the name of the region
region_params['region_name'].append(fov['name'])

# append the starting row and column coordinates
region_params['region_start_row'].append(fov['centerPointMicrons']['y'])
region_params['region_start_col'].append(fov['centerPointMicrons']['x'])
Expand All @@ -289,7 +292,7 @@ def read_tiled_region_inputs(region_corners, region_params):

# verify that the micron size specified is valid
if fov['fovSizeMicrons'] <= 0:
raise ValueError("The fovSizeMicrons field for region %s must be positive"
raise ValueError("The fovSizeMicrons field for FOVs in region %s must be positive"
% fov['name'])

print("Using FOV step size of %d microns for both row (y) and column (x) axis of region %s"
Expand Down Expand Up @@ -331,7 +334,7 @@ def read_tiled_region_inputs(region_corners, region_params):


def set_tiled_region_params(region_corners_path):
"""Given a file specifying FOV regions, set the MIBI tiling parameters.
"""Given a file specifying top-left FOVs for a set of regions, set the MIBI tiling parameters.

User inputs will be required for many values. Units used are microns.

Expand Down Expand Up @@ -547,7 +550,8 @@ def generate_tiled_region_fov_list(tiling_params, moly_path):
row_col_pairs = generate_x_y_fov_pairs(row_range, col_range)

# name the FOVs according to MIBI conventions
fov_names = ['R%dC%d' % (y + 1, x + 1) for x in range(region_info['fov_num_row'])
fov_names = ['%s_R%dC%d' % (region_info['region_name'], y + 1, x + 1)
for x in range(region_info['fov_num_row'])
for y in range(region_info['fov_num_col'])]

# randomize pairs list if specified
Expand Down
101 changes: 67 additions & 34 deletions toffy/tiling_utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,12 @@ def test_save_coreg_params():
cases=test_cases.TiledRegionReadCases, glob='*_no_moly_param')
def test_read_tiled_region_inputs(monkeypatch, fov_coords, fov_names, fov_sizes, user_inputs,
base_param_values, full_param_set):
# define a sample fovs list
# define a sample fovs list to define the top-left corners of each tiled region
sample_fovs_list = test_utils.generate_sample_fovs_list(
fov_coords=fov_coords, fov_names=fov_names, fov_sizes=fov_sizes
)

# define sample region_params to read data into
# define sample_region_params to read data into
sample_region_params = {rpf: [] for rpf in settings.REGION_PARAM_FIELDS}

# generate the user inputs
Expand Down Expand Up @@ -269,14 +269,14 @@ def test_generate_region_info():
@parametrize('region_corners_file', [param('bad_region_corners.json', marks=file_missing_err),
param('tiled_region_corners.json')])
@parametrize_with_cases(
'fov_coords, fov_names, fov_sizes, user_inputs, base_param_values,full_param_set',
'fov_coords, fov_names, fov_sizes, user_inputs, base_param_values, full_param_set',
cases=test_cases.TiledRegionReadCases, glob='*_with_moly_param'
)
@parametrize('moly_interval_val', [0, 1])
def test_set_tiled_region_params(monkeypatch, region_corners_file, fov_coords, fov_names,
fov_sizes, user_inputs, base_param_values,
full_param_set, moly_interval_val):
# define a sample set of fovs
# define a sample set of fovs to define the top-left corners of each tiled region
sample_fovs_list = test_utils.generate_sample_fovs_list(
fov_coords=fov_coords, fov_names=fov_names, fov_sizes=fov_sizes
)
Expand Down Expand Up @@ -351,19 +351,21 @@ def test_generate_x_y_fov_pairs_rhombus(coords, actual_pairs):


@parametrize_with_cases(
'moly_path, moly_region_setting, moly_interval_setting, moly_interval_value, '
'moly_insert_indices, fov_1_end_pos', cases=test_cases.TiledRegionMolySettingCases
'moly_path, moly_roi_setting, moly_interval_setting, moly_interval_value, '
'moly_insert_indices, roi_1_end_pos', cases=test_cases.TiledRegionMolySettingCases
)
@parametrize('randomize_setting', [['N', 'N'], ['N', 'Y'], ['Y', 'Y']])
def test_generate_tiled_region_fov_list(moly_path, moly_region_setting,
def test_generate_tiled_region_fov_list(moly_path, moly_roi_setting,
moly_interval_setting, moly_interval_value,
moly_insert_indices, fov_1_end_pos, randomize_setting):
sample_fovs_list = test_utils.generate_sample_fovs_list(
fov_coords=[(0, 0), (100, 100)], fov_names=["TheFirstFOV", "TheSecondFOV"],
moly_insert_indices, roi_1_end_pos, randomize_setting):
# define a set of fovs defining the upper-left corners of each region
sample_roi_fovs_list = test_utils.generate_sample_fovs_list(
fov_coords=[(0, 0), (100, 100)], fov_names=['TheFirstROI', 'TheSecondROI'],
fov_sizes=[5, 10]
)

sample_region_inputs = {
'region_name': ['TheFirstROI', 'TheSecondROI'],
'region_start_row': [100, 150],
'region_start_col': [0, 50],
'fov_num_row': [2, 4],
Expand All @@ -377,7 +379,7 @@ def test_generate_tiled_region_fov_list(moly_path, moly_region_setting,

sample_tiling_params = {
'fovFormatVersion': '1.5',
'fovs': sample_fovs_list['fovs'],
'fovs': sample_roi_fovs_list['fovs'],
'region_params': sample_region_params
}

Expand All @@ -390,26 +392,31 @@ def test_generate_tiled_region_fov_list(moly_path, moly_region_setting,
with open(sample_moly_path, 'w') as smp:
json.dump(sample_moly_point, smp)

sample_tiling_params['moly_region'] = moly_region_setting
sample_tiling_params['moly_region'] = moly_roi_setting

sample_tiling_params['region_params'][0]['region_rand'] = randomize_setting[0]
sample_tiling_params['region_params'][1]['region_rand'] = randomize_setting[1]

if moly_interval_setting:
sample_tiling_params['moly_interval'] = moly_interval_value

fov_regions = tiling_utils.generate_tiled_region_fov_list(
fov_list = tiling_utils.generate_tiled_region_fov_list(
sample_tiling_params, os.path.join(td, moly_path)
)

# assert none of the metadata keys explicitly added by set_tiling_params appear
for k in ['region_params', 'moly_region', 'moly_interval']:
assert k not in fov_regions
assert k not in fov_list

# retrieve the center points
center_points = [
(fov['centerPointMicrons']['x'], fov['centerPointMicrons']['y'])
for fov in fov_regions['fovs']
for fov in fov_list['fovs']
]

# retrieve the fov names
fov_names = [
fov['name'] for fov in fov_list['fovs']
]

# define the center points sorted
Expand All @@ -419,47 +426,73 @@ def test_generate_tiled_region_fov_list(moly_path, moly_region_setting,
(x, y) for x in np.arange(50, 90, 10) for y in list(reversed(np.arange(140, 160, 10)))
]

# define the corresponding FOV names
actual_fov_names = [
'TheFirstROI_R%dC%d' % (x, y) for y in np.arange(1, 3) for x in np.arange(1, 5)
] + [
'TheSecondROI_R%dC%d' % (x, y) for y in np.arange(1, 5) for x in np.arange(1, 3)
]

for mi in moly_insert_indices:
actual_center_points_sorted.insert(mi, (14540, -10830))
actual_fov_names.insert(mi, 'MoQC')

# easiest case: the center points should be sorted
# easiest case: the center points and FOV names should be sorted
if randomize_setting == ['N', 'N']:
assert center_points == actual_center_points_sorted
# if only the second fov is randomized
assert fov_names == actual_fov_names

# if only the second ROI is randomized
elif randomize_setting == ['N', 'Y']:
# ensure the fov 1 center points are the same for both sorted and random
assert center_points[:fov_1_end_pos] == actual_center_points_sorted[:fov_1_end_pos]
# ensure the ROI 1 center points and FOV names are the same for both sorted and random
assert center_points[:roi_1_end_pos] == actual_center_points_sorted[:roi_1_end_pos]
assert fov_names[:roi_1_end_pos] == actual_fov_names[:roi_1_end_pos]

# ensure the random center points for fov 2 contain the same elements
# ensure the random center points and fov names for ROI 2 contain the same elements
# as its sorted version
misc_utils.verify_same_elements(
computed_center_points=center_points[fov_1_end_pos:],
actual_center_points=actual_center_points_sorted[fov_1_end_pos:]
computed_center_points=center_points[roi_1_end_pos:],
actual_center_points=actual_center_points_sorted[roi_1_end_pos:]
)
misc_utils.verify_same_elements(
computed_fov_names=fov_names[roi_1_end_pos:],
actual_fov_names=actual_fov_names[roi_1_end_pos:]
)

# however, fov 2 sorted entries should NOT equal fov 2 random entries
assert center_points[fov_1_end_pos:] != actual_center_points_sorted[fov_1_end_pos:]
# however, ROI 2 sorted entries should NOT equal ROI 2 random entries
assert center_points[roi_1_end_pos:] != actual_center_points_sorted[roi_1_end_pos:]
assert fov_names[roi_1_end_pos:] != actual_fov_names[roi_1_end_pos:]
# if both fovs are randomized
elif randomize_setting == ['Y', 'Y']:
# ensure the random center points for fov 1 contain the same elements
# ensure the random center points and fov names for ROI 1 contain the same elements
# as its sorted version
misc_utils.verify_same_elements(
computed_center_points=center_points[:fov_1_end_pos],
actual_center_points=actual_center_points_sorted[:fov_1_end_pos]
computed_center_points=center_points[:roi_1_end_pos],
actual_center_points=actual_center_points_sorted[:roi_1_end_pos]
)
misc_utils.verify_same_elements(
computed_fov_names=fov_names[:roi_1_end_pos],
actual_fov_names=actual_fov_names[:roi_1_end_pos]
)

# however, fov 1 sorted entries should NOT equal fov 1 random entries
assert center_points[:fov_1_end_pos] != actual_center_points_sorted[:fov_1_end_pos]
# however, ROI 1 sorted entries should NOT equal ROI 1 random entries
assert center_points[:roi_1_end_pos] != actual_center_points_sorted[:roi_1_end_pos]
assert fov_names[:roi_1_end_pos] != actual_fov_names[:roi_1_end_pos]

# ensure the random center points for fov 2 contain the same elements
# ensure the random center points for ROI 2 contain the same elements
# as its sorted version
misc_utils.verify_same_elements(
computed_center_points=center_points[fov_1_end_pos:],
actual_center_points=actual_center_points_sorted[fov_1_end_pos:]
computed_center_points=center_points[roi_1_end_pos:],
actual_center_points=actual_center_points_sorted[roi_1_end_pos:]
)
misc_utils.verify_same_elements(
computed_fov_names=fov_names[roi_1_end_pos:],
actual_fov_names=actual_fov_names[roi_1_end_pos:]
)

# however, fov 2 sorted entries should NOT equal fov 2 random entries
assert center_points[fov_1_end_pos:] != actual_center_points_sorted[fov_1_end_pos:]
# however, ROI 2 sorted entries should NOT equal ROI 2 random entries
assert center_points[roi_1_end_pos:] != actual_center_points_sorted[roi_1_end_pos:]
assert fov_names[roi_1_end_pos:] != actual_fov_names[roi_1_end_pos:]


@parametrize_with_cases('top_left, top_right, bottom_left, bottom_right',
Expand Down
Loading