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
示例#4
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')