def test_spot_finding_reference_image_sequential( data_stack: ImageStack, spot_detector: FindSpotsAlgorithm, max_intensity: float, ): """ This testing method uses a reference image to identify spot locations then builds traces using the sequential strategy. It finds 2 spots in the max projected image, then measures the two spots on each tile totally 2*num_chs*num_rounds spots. When building spot traces it treats each spot as it's own trace totally 8 traces. This workflow doesn't really make sense but we're testing it anyway. """ reference_image = data_stack.reduce((Axes.ROUND, Axes.CH), func="max", module=FunctionSource.np) spots = spot_detector.run(image_stack=data_stack, reference_image=reference_image) intensity_table = trace_builders.build_traces_sequential(spots) expected_num_traces = (2 * data_stack.num_chs * data_stack.num_rounds) assert intensity_table.sizes[Features.AXIS] == expected_num_traces, "wrong number of " \ "spots traces detected" reference_image = EMPTY_IMAGESTACK.reduce((Axes.ROUND, Axes.CH), func="max", module=FunctionSource.np) spots = spot_detector.run(image_stack=EMPTY_IMAGESTACK, reference_image=reference_image) empty_intensity_table = trace_builders.build_traces_sequential(spots) assert empty_intensity_table.sizes[Features.AXIS] == 0
def run(self, spots: SpotFindingResults, *args) -> DecodedIntensityTable: """ Decode spots by looking up the associated target value for the round and ch each spot is in. Parameters ---------- spots: SpotFindingResults A Dict of tile indices and their corresponding measured spots Returns ------- DecodedIntensityTable : IntensityTable decoded and appended with Features.TARGET and values. """ lookup_table: Dict[Tuple, str] = {} for target in self.codebook[Features.TARGET]: for ch_label in self.codebook[Axes.CH.value]: for round_label in self.codebook[Axes.ROUND.value]: if self.codebook.loc[target, round_label, ch_label]: lookup_table[(int(round_label), int(ch_label))] = str(target.values) for r_ch_index, results in spots.items(): target = lookup_table[ r_ch_index] if r_ch_index in lookup_table else 'nan' results.spot_attrs.data[Features.TARGET] = target intensities = build_traces_sequential(spots) return DecodedIntensityTable(intensities)
def test_spot_finding_no_reference_image_sequential( data_stack: ImageStack, spot_detector: FindSpotsAlgorithm, max_intensity: float, ): """ This testing method does not provide a reference image, and should therefore check for spots in each (round, ch) combination in sequence. With the given input, it should detect 4 spots. It then uses the sequential trace building strategy which should treat each spot as it's own unique trace totalling 4 traces. """ spots = spot_detector.run(image_stack=data_stack) intensity_table = trace_builders.build_traces_sequential(spots) assert intensity_table.sizes[Features.AXIS] == 4, "wrong number of spot traces detected" expected = [max_intensity] * 4 assert np.allclose(intensity_table.sum((Axes.ROUND, Axes.CH)).values, expected), \ "wrong spot intensities detected" spots = spot_detector.run(image_stack=EMPTY_IMAGESTACK) empty_intensity_table = trace_builders.build_traces_sequential(spots) assert empty_intensity_table.sizes[Features.AXIS] == 0
# Typical pipelines will set the ``trace_building_strategy`` as an argument in the # :py:class:`.DecodeSpotsAlgorithm` but here the underlying code is exposed to reveal what the # different :py:class:`.IntensityTable`\s look like depending on which ``TraceBuilder`` is used. from starfish.core.spots.DecodeSpots.trace_builders import build_spot_traces_exact_match, \ build_traces_sequential, build_traces_nearest_neighbors print('Build trace with EXACT_MATCH') print(build_spot_traces_exact_match(spots_from_ref)) #################################################################################################### # When building spot traces with EXACT_MATCH, every feature has a value in each round and channel # because a ``reference_image`` was used in spot finding. print('\nBuild trace with SEQUENTIAL') print(build_traces_sequential(spots_from_stack)) #################################################################################################### # When building spot traces with SEQUENTIAL, every feature has only one non-zero round and channel # because :py:func:`.build_traces_sequential` automatically assigns a zero value to all other # rounds and channels. print('\nBuild trace with NEAREST_NEIGHBORS') print(build_traces_nearest_neighbors(spots_from_stack, search_radius=5)) #################################################################################################### # When building spot traces with NEAREST_NEIGHBORS on spots found in :py:class:`.ImageStack` # without a ``reference image``, the ``nan`` values are due to no spot being found within the # ``search_radius`` of the ``anchor_round``. print('\nBuild trace with NEAREST_NEIGHBORS')