Scenario - Snailz Docs

Skip to content

# Scenario

Entire scenario.

## `Scenario`

Bases: `BaseModel`

Entire synthetic data scenario.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`params` | `ScenarioParams` | scenario parameters | required
`grids` | `list[Grid]` | sample site grids | `<dynamic>`
`specimens` | `AllSpecimens` | all specimens | required
`machines` | `list[Machine]` | laboratory machines | required
`persons` | `list[Person]` | lab staff | required
`assays` | `list[Assay]` | assays | required
`images` | `dict[str, Image]` | assay images | required

Source code in `src/snailz/scenario.py`

     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    class Scenario(BaseModel):
        """Entire synthetic data scenario."""

        params: ScenarioParams = Field(description="scenario parameters")
        grids: list[Grid] = Field(default_factory=list, description="sample site grids")
        specimens: AllSpecimens = Field(description="all specimens")
        sampled: dict[str, tuple[str, tuple[int, int]]] = Field(
            default_factory=dict, description="where specimens taken"
        )
        machines: list[Machine] = Field(
            default_factory=[], description="laboratory machines"
        )
        persons: list[Person] = Field(default_factory=[], description="lab staff")
        assays: list[Assay] = Field(default_factory=[], description="assays")
        images: dict[str, Image] = Field(default_factory={}, description="assay images")

        # Allow arbitrary types to handle Image
        model_config = {"arbitrary_types_allowed": True, "extra": "forbid"}

        @staticmethod
        def generate(params):
            """Generate entire scenario."""
            grids = [Grid.generate(params.grid_size) for _ in range(params.num_sites)]
            specimens = AllSpecimens.generate(params.specimen_params, params.num_specimens)
            machines = Machine.generate(params.num_machines)
            persons = Person.generate(params.locale, params.num_persons)

            assays = []
            for s in specimens.samples:
                for i in range(params.assays_per_specimen):
                    assays.append(
                        Assay.generate(
                            params.assay_params,
                            s,
                            random.choice(machines),
                            random.choice(persons),
                        )
                    )

            scaling = float(math.ceil(_max_reading(assays) + 1))
            images = {a.id: make_image(params.assay_params, a, scaling) for a in assays}

            return Scenario(
                params=params,
                grids=grids,
                specimens=specimens,
                sampled=Scenario.sample(params.grid_size, grids, specimens.samples),
                machines=Machine.generate(params.num_machines),
                persons=Person.generate(params.locale, params.num_persons),
                assays=assays,
                images=images,
            )

        @staticmethod
        def sample(size, grids, specimens):
            """Allocate specimens to grids."""
            grid_ids = [g.id for g in grids]
            coords = {
                g.id: [(x, y) for x in range(size) for y in range(size)] for g in grids
            }
            result = {}
            for s in specimens:
                gid = random.choice(grid_ids)
                loc = random.choice(range(len(coords[gid])))
                result[s.id] = (gid, coords[gid][loc])
                del coords[gid][loc]
            return result

        def to_csv(self, root):
            """Write to multi-CSV."""

            root = Path(root)
            root.mkdir(exist_ok=True)

            with open(root / "machines.csv", "w") as stream:
                Machine.to_csv(csv.writer(stream), self.machines)

            with open(root / "persons.csv", "w") as stream:
                Person.to_csv(csv.writer(stream), self.persons)

            for grid in self.grids:
                with open(root / f"{grid.id}.csv", "w") as stream:
                    Grid.to_csv(csv.writer(stream), grid)

            with open(root / "specimens.csv", "w") as stream:
                self.specimens.to_csv(csv.writer(stream))

            with open(root / "assays.csv", "w") as stream:
                Assay.all_csv(csv.writer(stream), self.assays)

            for assay in self.assays:
                treatments_file = root / f"{assay.id}_treatments.csv"
                with open(treatments_file, "w") as stream:
                    assay.to_csv(csv.writer(stream), False)

                readings_file = root / f"{assay.id}_readings.csv"
                raw_file = root / f"{assay.id}_raw.csv"
                with open(readings_file, "w") as stream:
                    assay.to_csv(csv.writer(stream), True)
                mangle_assay(readings_file, raw_file, self.persons)

            for id, img in self.images.items():
                img_file = root / f"{id}.png"
                img.save(img_file)

### `generate(params)` `staticmethod`

Generate entire scenario.

Source code in `src/snailz/scenario.py`

    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    @staticmethod
    def generate(params):
        """Generate entire scenario."""
        grids = [Grid.generate(params.grid_size) for _ in range(params.num_sites)]
        specimens = AllSpecimens.generate(params.specimen_params, params.num_specimens)
        machines = Machine.generate(params.num_machines)
        persons = Person.generate(params.locale, params.num_persons)

        assays = []
        for s in specimens.samples:
            for i in range(params.assays_per_specimen):
                assays.append(
                    Assay.generate(
                        params.assay_params,
                        s,
                        random.choice(machines),
                        random.choice(persons),
                    )
                )

        scaling = float(math.ceil(_max_reading(assays) + 1))
        images = {a.id: make_image(params.assay_params, a, scaling) for a in assays}

        return Scenario(
            params=params,
            grids=grids,
            specimens=specimens,
            sampled=Scenario.sample(params.grid_size, grids, specimens.samples),
            machines=Machine.generate(params.num_machines),
            persons=Person.generate(params.locale, params.num_persons),
            assays=assays,
            images=images,
        )

### `sample(size, grids, specimens)` `staticmethod`

Allocate specimens to grids.

Source code in `src/snailz/scenario.py`

    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    @staticmethod
    def sample(size, grids, specimens):
        """Allocate specimens to grids."""
        grid_ids = [g.id for g in grids]
        coords = {
            g.id: [(x, y) for x in range(size) for y in range(size)] for g in grids
        }
        result = {}
        for s in specimens:
            gid = random.choice(grid_ids)
            loc = random.choice(range(len(coords[gid])))
            result[s.id] = (gid, coords[gid][loc])
            del coords[gid][loc]
        return result

### `to_csv(root)`

Write to multi-CSV.

Source code in `src/snailz/scenario.py`

     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    def to_csv(self, root):
        """Write to multi-CSV."""

        root = Path(root)
        root.mkdir(exist_ok=True)

        with open(root / "machines.csv", "w") as stream:
            Machine.to_csv(csv.writer(stream), self.machines)

        with open(root / "persons.csv", "w") as stream:
            Person.to_csv(csv.writer(stream), self.persons)

        for grid in self.grids:
            with open(root / f"{grid.id}.csv", "w") as stream:
                Grid.to_csv(csv.writer(stream), grid)

        with open(root / "specimens.csv", "w") as stream:
            self.specimens.to_csv(csv.writer(stream))

        with open(root / "assays.csv", "w") as stream:
            Assay.all_csv(csv.writer(stream), self.assays)

        for assay in self.assays:
            treatments_file = root / f"{assay.id}_treatments.csv"
            with open(treatments_file, "w") as stream:
                assay.to_csv(csv.writer(stream), False)

            readings_file = root / f"{assay.id}_readings.csv"
            raw_file = root / f"{assay.id}_raw.csv"
            with open(readings_file, "w") as stream:
                assay.to_csv(csv.writer(stream), True)
            mangle_assay(readings_file, raw_file, self.persons)

        for id, img in self.images.items():
            img_file = root / f"{id}.png"
            img.save(img_file)

## `_max_reading(assays)`

Find maximum reading across all assays.

Source code in `src/snailz/scenario.py`

    128
    129
    130
    131
    132
    133
    134
    135
    136
    def _max_reading(assays):
        """Find maximum reading across all assays."""

        result = 0.0
        for a in assays:
            for x in range(a.readings.size):
                for y in range(a.readings.size):
                    result = max(result, a.readings[x, y])
        return result