Пример #1
0
def composite_codebook() -> Tuple[Codebook, ImageStack]:
    """
    Produce an Imagestack representing a composite experiment where the first 2 rounds are
    multiplexed data and the last round is sequential data.

    Returns
    -------
    Codebook :
        codebook containing codes that match the data
    ImageStack :
        noiseless ImageStack containing one spot per code in codebook
    """
    codebook_data = [{
        Features.CODEWORD: [{
            Axes.ROUND.value: 0,
            Axes.CH.value: 0,
            Features.CODE_VALUE: 1
        }, {
            Axes.ROUND.value: 1,
            Axes.CH.value: 1,
            Features.CODE_VALUE: 1
        }],
        Features.TARGET:
        "GENE_A"
    }, {
        Features.CODEWORD: [{
            Axes.ROUND.value: 0,
            Axes.CH.value: 1,
            Features.CODE_VALUE: 1
        }, {
            Axes.ROUND.value: 1,
            Axes.CH.value: 0,
            Features.CODE_VALUE: 1
        }],
        Features.TARGET:
        "GENE_B"
    }, {
        Features.CODEWORD: [{
            Axes.ROUND.value: 2,
            Axes.CH.value: 0,
            Features.CODE_VALUE: 1
        }],
        Features.TARGET:
        "GENE_C"
    }, {
        Features.CODEWORD: [{
            Axes.ROUND.value: 2,
            Axes.CH.value: 1,
            Features.CODE_VALUE: 1
        }],
        Features.TARGET:
        "GENE_D"
    }]

    codebook = Codebook.from_code_array(codebook_data)
    imagestack = create_imagestack_from_codebook(
        pixel_dimensions=(10, 100, 100),
        spot_coordinates=((4, 10, 90), (5, 90, 10), (6, 90, 10), (7, 90, 10)),
        codebook=codebook)
    return codebook, imagestack
Пример #2
0
def seqfishCodebook(nRound, nChannel, nCodes):
    def barcodeConv(lis, chs):
        barcode = np.zeros((len(lis), chs))
        for i in range(len(lis)):
            barcode[i][lis[i]] = 1
        return barcode

    def incrBarcode(lis, chs):
        currInd = len(lis) - 1
        lis[currInd] += 1
        while lis[currInd] == chs:
            lis[currInd] = 0
            currInd -= 1
            lis[currInd] += 1
        return lis

    allCombo = np.zeros((nChannel**nRound, nRound, nChannel))

    barcode = [0] * nRound
    for i in range(np.shape(allCombo)[0]):
        allCombo[i] = barcodeConv(barcode, nChannel)
        barcode = incrBarcode(barcode, nChannel)

    hammingDistance = 1
    blanks = []
    i = 0
    while i < len(allCombo):
        blanks.append(allCombo[i])
        j = i + 1
        while j < len(allCombo):
            if np.count_nonzero(
                    ~(allCombo[i] == allCombo[j])) / 2 <= hammingDistance:
                allCombo = allCombo[[
                    k for k in range(len(allCombo)) if k != j
                ]]
            else:
                j += 1
        i += 1

    data = np.asarray(blanks)[random.sample(range(len(blanks)), nCodes)]

    return Codebook.from_numpy(code_names=range(len(data)),
                               n_round=nRound,
                               n_channel=nChannel,
                               data=data)
Пример #3
0
    def from_json(cls, json_url: str) -> "Experiment":
        """
        Construct an Experiment from an experiment.json file format specifier.
        Loads configuration from StarfishConfig.

        Parameters
        ----------
        json_url : str
            file path or web link to an experiment.json file

        Returns
        -------
        Experiment :
            Experiment object serving the requested experiment data

        """

        config = StarfishConfig()

        if config.strict:
            valid = validate_sptx.validate(json_url)
            if not valid:
                raise Exception("validation failed")

        backend, name, baseurl = resolve_path_or_url(json_url, config.slicedimage)
        with backend.read_contextmanager(name) as fh:
            experiment_document = json.load(fh)

        version = cls.verify_version(experiment_document['version'])

        _, codebook_name, codebook_baseurl = resolve_url(experiment_document['codebook'],
                                                         baseurl, config.slicedimage)
        codebook_absolute_url = pathjoin(codebook_baseurl, codebook_name)
        codebook = Codebook.open_json(codebook_absolute_url)

        extras = experiment_document['extras']

        fovs: MutableSequence[FieldOfView] = list()
        fov_tilesets: MutableMapping[str, TileSet]
        if version < Version("5.0.0"):
            primary_image: Collection = Reader.parse_doc(experiment_document['primary_images'],
                                                         baseurl, config.slicedimage)
            auxiliary_images: MutableMapping[str, Collection] = dict()
            for aux_image_type, aux_image_url in experiment_document['auxiliary_images'].items():
                auxiliary_images[aux_image_type] = Reader.parse_doc(
                    aux_image_url, baseurl, config.slicedimage)

            for fov_name, primary_tileset in primary_image.all_tilesets():
                fov_tilesets = dict()
                fov_tilesets[FieldOfView.PRIMARY_IMAGES] = primary_tileset
                for aux_image_type, aux_image_collection in auxiliary_images.items():
                    aux_image_tileset = aux_image_collection.find_tileset(fov_name)
                    if aux_image_tileset is not None:
                        fov_tilesets[aux_image_type] = aux_image_tileset

                fov = FieldOfView(fov_name, image_tilesets=fov_tilesets)
                fovs.append(fov)
        else:
            images: MutableMapping[str, Collection] = dict()
            all_fov_names: MutableSet[str] = set()
            for image_type, image_url in experiment_document['images'].items():
                image = Reader.parse_doc(image_url, baseurl, config.slicedimage)
                images[image_type] = image
                for fov_name, _ in image.all_tilesets():
                    all_fov_names.add(fov_name)

            for fov_name in all_fov_names:
                fov_tilesets = dict()
                for image_type, image_collection in images.items():
                    image_tileset = image_collection.find_tileset(fov_name)
                    if image_tileset is not None:
                        fov_tilesets[image_type] = image_tileset

                fov = FieldOfView(fov_name, image_tilesets=fov_tilesets)
                fovs.append(fov)

        return Experiment(fovs, codebook, extras, src_doc=experiment_document)
Пример #4
0
def write_irregular_experiment_json(
        path: str,
        tile_format: ImageFormat,
        *,
        image_tile_identifiers: Mapping[str, Iterable[TileIdentifier]],
        tile_fetchers: Mapping[str, TileFetcher],
        postprocess_func: Optional[Callable[[dict], dict]]=None,
        default_shape: Optional[Mapping[Axes, int]]=None,
        fov_path_generator: Callable[[Path, str], Path] = None,
        tile_opener: Optional[Callable[[Path, Tile, str], BinaryIO]] = None,
) -> None:
    """
    Build and returns a top-level experiment description with the following characteristics:

    Parameters
    ----------
    path : str
        Directory to write the files to.
    tile_format : ImageFormat
        File format to write the tiles as.
    image_tile_identifiers : Mapping[str, Iterable[TileIdentifier]]
        Dictionary mapping the image type to an iterable of TileIdentifiers.
    tile_fetchers : Mapping[str, TileFetcher]
        Dictionary mapping the image type to a TileFetcher.
    postprocess_func : Optional[Callable[[dict], dict]]
        If provided, this is called with the experiment document for any postprocessing.
        An example of this would be to add something to one of the top-level extras field.
        The callable should return what is to be written as the experiment document.
    default_shape : Optional[Tuple[int, int]] (default = None)
        Default shape for the tiles in this experiment.
    fov_path_generator : Optional[Callable[[Path, str], Path]]
        Generates the path for a FOV's json file.  If one is not provided, the default generates
        the FOV's json file at the same level as the top-level json file for an image.    If this is
        not provided, a reasonable default will be provided.
    tile_opener : Optional[Callable[[Path, Tile, str], BinaryIO]]
        Callable that gets invoked with the following arguments: 1. the directory of the experiment
        that is being constructed, 2. the tile that is being written, and 3. the file extension
        that the tile should be written with.  The callable is expected to return an open file
        handle.  If this is not provided, a reasonable default will be provided.
    """
    if postprocess_func is None:
        postprocess_func = lambda doc: doc
    if fov_path_generator is None:
        fov_path_generator = _fov_path_generator
    if tile_opener is None:
        tile_opener = _tile_opener

    experiment_doc: Dict[str, Any] = {
        'version': str(CURRENT_VERSION),
        'images': {},
        'extras': {},
    }
    for image_type, tile_identifiers in image_tile_identifiers.items():
        tile_fetcher = tile_fetchers[image_type]

        image = build_irregular_image(tile_identifiers, tile_fetcher, default_shape)

        Writer.write_to_path(
            image,
            os.path.join(path, f"{image_type}.json"),
            pretty=True,
            partition_path_generator=fov_path_generator,
            tile_opener=tile_opener,
            tile_format=tile_format,
        )
        experiment_doc['images'][image_type] = f"{image_type}.json"

    experiment_doc["codebook"] = "codebook.json"
    codebook_array = [
        {
            "codeword": [
                {"r": 0, "c": 0, "v": 1},
            ],
            "target": "PLEASE_REPLACE_ME"
        },
    ]
    codebook = Codebook.from_code_array(codebook_array)
    codebook_json_filename = "codebook.json"
    codebook.to_json(os.path.join(path, codebook_json_filename))

    experiment_doc = postprocess_func(experiment_doc)

    with open(os.path.join(path, "experiment.json"), "w") as fh:
        json.dump(experiment_doc, fh, indent=4)
Пример #5
0
def write_experiment_json(
    path: str,
    fov_count: int,
    tile_format: ImageFormat,
    *,
    primary_image_dimensions: Mapping[Union[str, Axes], int],
    aux_name_to_dimensions: Mapping[str, Mapping[Union[str, Axes], int]],
    primary_tile_fetcher: Optional[TileFetcher] = None,
    aux_tile_fetcher: Optional[Mapping[str, TileFetcher]] = None,
    postprocess_func: Optional[Callable[[dict], dict]] = None,
    default_shape: Optional[Mapping[Axes, int]] = None,
    dimension_order: Sequence[Axes] = (Axes.ZPLANE, Axes.ROUND, Axes.CH),
    fov_path_generator: Callable[[Path, str], Path] = _fov_path_generator,
    tile_opener: Callable[[Path, Tile, str], BinaryIO] = _tile_opener,
) -> None:
    """
    Build and returns a top-level experiment description with the following characteristics:

    Parameters
    ----------
    path : str
        Directory to write the files to.
    fov_count : int
        Number of fields of view in this experiment.
    tile_format : ImageFormat
        File format to write the tiles as.
    primary_image_dimensions : Mapping[Union[str, Axes], int]
        Dictionary mapping dimension name to dimension size for the primary image.
    aux_name_to_dimensions : Mapping[str, Mapping[Union[str, Axes], int]]
        Dictionary mapping the auxiliary image type to dictionaries, which map from dimension name
        to dimension size.
    primary_tile_fetcher : Optional[TileFetcher]
        TileFetcher for primary images.  Set this if you want specific image data to be set for the
        primary images.  If not provided, the image data is set to random noise via
        :class:`RandomNoiseTileFetcher`.
    aux_tile_fetcher : Optional[Mapping[str, TileFetcher]]
        TileFetchers for auxiliary images.  Set this if you want specific image data to be set for
        one or more aux image types.  If not provided for any given aux image, the image data is
        set to random noise via :class:`RandomNoiseTileFetcher`.
    postprocess_func : Optional[Callable[[dict], dict]]
        If provided, this is called with the experiment document for any postprocessing.
        An example of this would be to add something to one of the top-level extras field.
        The callable should return what is to be written as the experiment document.
    default_shape : Optional[Tuple[int, int]] (default = None)
        Default shape for the tiles in this experiment.
    dimension_order : Sequence[Axes]
        Ordering for which dimensions vary, in order of the slowest changing dimension to the
        fastest.  For instance, if the order is (ROUND, Z, CH) and each dimension has size 2, then
        the sequence is:
          (ROUND=0, CH=0, Z=0)
          (ROUND=0, CH=1, Z=0)
          (ROUND=0, CH=0, Z=1)
          (ROUND=0, CH=1, Z=1)
          (ROUND=1, CH=0, Z=0)
          (ROUND=1, CH=1, Z=0)
          (ROUND=1, CH=0, Z=1)
          (ROUND=1, CH=1, Z=1)
        (default = (Axes.Z, Axes.ROUND, Axes.CH))
    fov_path_generator : Callable[[Path, str], Path]
        Generates the path for a FOV's json file.  If one is not provided, the default generates
        the FOV's json file at the same level as the top-level json file for an image.
    tile_opener : Callable[[Path, Tile, str], BinaryIO]
    """
    if primary_tile_fetcher is None:
        primary_tile_fetcher = tile_fetcher_factory(RandomNoiseTile)
    if aux_tile_fetcher is None:
        aux_tile_fetcher = {}
    if postprocess_func is None:
        postprocess_func = lambda doc: doc

    experiment_doc: Dict[str, Any] = {
        'version': str(CURRENT_VERSION),
        'images': {},
        'extras': {},
    }
    primary_image = build_image(
        range(fov_count),
        range(primary_image_dimensions[Axes.ROUND]),
        range(primary_image_dimensions[Axes.CH]),
        range(primary_image_dimensions[Axes.ZPLANE]),
        primary_tile_fetcher,
        axes_order=dimension_order,
        default_shape=default_shape,
    )
    Writer.write_to_path(
        primary_image,
        os.path.join(path, "primary_images.json"),
        pretty=True,
        partition_path_generator=fov_path_generator,
        tile_opener=tile_opener,
        tile_format=tile_format,
    )
    experiment_doc['images']['primary'] = "primary_images.json"

    for aux_name, aux_dimensions in aux_name_to_dimensions.items():
        if aux_dimensions is None:
            continue
        auxiliary_image = build_image(
            range(fov_count),
            range(aux_dimensions[Axes.ROUND]),
            range(aux_dimensions[Axes.CH]),
            range(aux_dimensions[Axes.ZPLANE]),
            aux_tile_fetcher.get(aux_name,
                                 tile_fetcher_factory(RandomNoiseTile)),
            axes_order=dimension_order,
            default_shape=default_shape,
        )
        Writer.write_to_path(
            auxiliary_image,
            os.path.join(path, "{}.json".format(aux_name)),
            pretty=True,
            partition_path_generator=fov_path_generator,
            tile_opener=tile_opener,
            tile_format=tile_format,
        )
        experiment_doc['images'][aux_name] = "{}.json".format(aux_name)

    experiment_doc["codebook"] = "codebook.json"
    codebook_array = [
        {
            "codeword": [
                {
                    "r": 0,
                    "c": 0,
                    "v": 1
                },
            ],
            "target": "PLEASE_REPLACE_ME"
        },
    ]
    codebook = Codebook.from_code_array(codebook_array)
    codebook_json_filename = "codebook.json"
    codebook.to_json(os.path.join(path, codebook_json_filename))

    experiment_doc = postprocess_func(experiment_doc)

    with open(os.path.join(path, "experiment.json"), "w") as fh:
        json.dump(experiment_doc, fh, indent=4)
Пример #6
0
def composite_codebook_mixed_round() -> Tuple[Codebook, ImageStack]:
    """
    Produce an Imagestack representing a composite experiment where the first 2 and a half rounds
    are multiplexed data and the last round and a half is sequential data. This represents the type
    of hybrid experiment happening at the allen.

    Returns
    -------
    Codebook :
        codebook containing codes that match the data
    ImageStack :
        noiseless ImageStack containing one spot per code in codebook
    """
    codebook_data = [
        {
            Features.CODEWORD: [{
                Axes.ROUND.value: 0,
                Axes.CH.value: 0,
                Features.CODE_VALUE: 1
            }, {
                Axes.ROUND.value: 1,
                Axes.CH.value: 1,
                Features.CODE_VALUE: 1
            }],
            Features.TARGET:
            "GENE_A"
        },
        {
            Features.CODEWORD: [{
                Axes.ROUND.value: 0,
                Axes.CH.value: 1,
                Features.CODE_VALUE: 1
            }, {
                Axes.ROUND.value: 1,
                Axes.CH.value: 0,
                Features.CODE_VALUE: 1
            }],
            Features.TARGET:
            "GENE_B"
        },
        {
            Features.CODEWORD: [{
                Axes.ROUND.value: 2,
                Axes.CH.value: 0,
                Features.CODE_VALUE: 1
            }, {
                Axes.ROUND.value: 1,
                Axes.CH.value: 1,
                Features.CODE_VALUE: 1
            }],
            Features.TARGET:
            "GENE_C"
        },
        {
            Features.CODEWORD: [{
                Axes.ROUND.value: 2,
                Axes.CH.value: 2,
                Features.CODE_VALUE: 1
            }],
            Features.TARGET:
            "GENE_D"
        },
        {
            Features.CODEWORD: [{
                Axes.ROUND.value: 3,
                Axes.CH.value: 0,
                Features.CODE_VALUE: 1
            }],
            Features.TARGET:
            "GENE_E"
        },
    ]

    codebook = Codebook.from_code_array(codebook_data)
    imagestack = create_imagestack_from_codebook(
        pixel_dimensions=(1, 10, 10),
        spot_coordinates=((0, 5, 6), (0, 2, 3), (0, 7, 1), (0, 8, 2), (0, 3,
                                                                       6)),
        codebook=codebook)
    return codebook, imagestack
Пример #7
0
def compostie_codebook_seperate_stacks(
) -> Tuple[Codebook, ImageStack, ImageStack]:
    """
    Produce separate different sized ImageStacks containing data from two different experiment
    types (multiplexed and non multiplexed) and one codebook with the information for both.

    Returns
    -------
    Codebook :
        codebook containing codes that match the data
    ImageStack :
        noiseless ImageStack containing one spot per code in codebook
    """

    # 3 round 3 ch multiplexed data
    multiplexed_data = [
        {
            Features.CODEWORD: [{
                Axes.ROUND.value: 0,
                Axes.CH.value: 0,
                Features.CODE_VALUE: 1
            }, {
                Axes.ROUND.value: 2,
                Axes.CH.value: 1,
                Features.CODE_VALUE: 1
            }],
            Features.TARGET:
            "GENE_A"
        },
        {
            Features.CODEWORD: [{
                Axes.ROUND.value: 0,
                Axes.CH.value: 1,
                Features.CODE_VALUE: 1
            }, {
                Axes.ROUND.value: 1,
                Axes.CH.value: 2,
                Features.CODE_VALUE: 1
            }],
            Features.TARGET:
            "GENE_B"
        },
    ]
    codebook = Codebook.from_code_array(multiplexed_data)
    multiplexed_stack = create_imagestack_from_codebook(
        pixel_dimensions=(10, 100, 100),
        spot_coordinates=((4, 10, 90), (5, 90, 10)),
        codebook=codebook)

    # 3 rounds 1 ch non multiplexed data
    sequential_data = [{
        Features.CODEWORD: [{
            Axes.ROUND.value: 3,
            Axes.CH.value: 1,
            Features.CODE_VALUE: 1
        }],
        Features.TARGET:
        "GENE_C"
    }, {
        Features.CODEWORD: [{
            Axes.ROUND.value: 4,
            Axes.CH.value: 0,
            Features.CODE_VALUE: 1
        }],
        Features.TARGET:
        "GENE_D"
    }, {
        Features.CODEWORD: [{
            Axes.ROUND.value: 5,
            Axes.CH.value: 1,
            Features.CODE_VALUE: 1
        }],
        Features.TARGET:
        "GENE_D"
    }]
    codebook = Codebook.from_code_array(sequential_data)
    sequential_stack = create_imagestack_from_codebook(
        pixel_dimensions=(10, 100, 100),
        spot_coordinates=((4, 10, 90), (5, 90, 10), (7, 90, 10)),
        codebook=codebook)
    sequential_stack = sequential_stack.sel(indexers={Axes.ROUND: (3, 6)})

    # create codebook with combined target values
    combined = [{
        Features.CODEWORD: [{
            Axes.ROUND.value: 0,
            Axes.CH.value: 0,
            Features.CODE_VALUE: 1
        }, {
            Axes.ROUND.value: 2,
            Axes.CH.value: 1,
            Features.CODE_VALUE: 1
        }],
        Features.TARGET:
        "GENE_A"
    }, {
        Features.CODEWORD: [{
            Axes.ROUND.value: 0,
            Axes.CH.value: 1,
            Features.CODE_VALUE: 1
        }, {
            Axes.ROUND.value: 1,
            Axes.CH.value: 2,
            Features.CODE_VALUE: 1
        }],
        Features.TARGET:
        "GENE_B"
    }, {
        Features.CODEWORD: [{
            Axes.ROUND.value: 3,
            Axes.CH.value: 1,
            Features.CODE_VALUE: 1
        }],
        Features.TARGET:
        "GENE_C"
    }, {
        Features.CODEWORD: [{
            Axes.ROUND.value: 4,
            Axes.CH.value: 0,
            Features.CODE_VALUE: 1
        }],
        Features.TARGET:
        "GENE_D"
    }, {
        Features.CODEWORD: [{
            Axes.ROUND.value: 5,
            Axes.CH.value: 1,
            Features.CODE_VALUE: 1
        }],
        Features.TARGET:
        "GENE_E"
    }]
    codebook = Codebook.from_code_array(combined)
    return codebook, multiplexed_stack, sequential_stack
Пример #8
0
 def load(self, input_parameter: str) -> Codebook:
     return Codebook.open_json(input_parameter)