Species - Snailz Docs

Skip to content

# Species

Details of snail species.

## `Species` `dataclass`

Bases: `BaseMixin`

A set of generated specimens.

Attributes:

Name | Type | Description
--- | --- | ---
`reference` | `str` | reference genome
`loci` | `list[int]` | locations within genome of possible mutations
`susc_locus` | `int` | locus of susceptibility mutation
`susc_base` | `str` | base at `susc_locus` conferring mutation

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

     21
     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
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    @dataclass
    class Species(BaseMixin):
        """
        A set of generated specimens.

        Attributes:
            reference: reference genome
            loci: locations within genome of possible mutations
            susc_locus: locus of susceptibility mutation
            susc_base: base at `susc_locus` conferring mutation
        """

        pivot_keys: ClassVar[set[str]] = {"loci"}
        table_name: ClassVar[str] = "species"

        reference: str = ""
        loci: list[int] = field(default_factory=list)
        susc_locus: int = 0
        susc_base: str = ""

        @classmethod
        def make(cls, params: Parameters) -> list[Self]:
            """
            Construct a list containing a single species. (The result
            is returned in a list to be consistent with other classes'
            `make` methods.)

            Args:
                params: Parameters object.

            Returns:
                List containin a single `Species`.
            """
            reference = cls._reference_genome(params)
            loci = cls._random_loci(params, reference)
            susc_locus = random.choice(loci)
            susc_base = random.choice(BASES[reference[susc_locus]])
            return [
                Species(
                    reference=reference,
                    loci=loci,
                    susc_locus=susc_locus,
                    susc_base=susc_base,
                )
            ]

        @classmethod
        def save_csv(cls, outdir: Path | str, species: list[Self]):
            """
            Save species as CSV. `species` must be passed in a list to be
            consistent with other classes' `save_csv` methods. Scalar
            properties of the species are saved in one file; mutation loci
            values are pivoted to long form and saved in a separate file.

            Args:
                outdir: Output directory.
                species: List containing `Species` to save.

            """

            assert isinstance(species, list)
            super().save_csv(outdir, species)

            with open(Path(outdir, "species_loci.csv"), "w", newline="") as stream:
                objects = species[0]._loci_to_dict()
                writer = cls._csv_dict_writer(stream, list(objects[0].keys()))
                for obj in objects:
                    writer.writerow(obj)

        @classmethod
        def save_db(cls, db: Database, species: list[Self]):
            """
            Save species to database. `species` must be passed in a
            list to be consistent with other classes' `save_csv` methods.
            Scalar properties of the species are saved in one table;
            mutation loci values are pivoted to long form and saved in a
            separate table.

            Args:
                db: Database connector.
                species: List containing `Species` to save.
            """

            assert isinstance(species, list)
            super().save_db(db, species)
            table = db["species_loci"]
            table.insert_all(species[0]._loci_to_dict(), pk="ident")

        @classmethod
        def _random_loci(cls, params: Parameters, reference: str) -> list[int]:
            """
            Generate random loci for mutations.

            Args:
                params: Parameters object.
                reference: Reference genome.

            Returns:
                List of indices of locations where mutations might occur.
            """

            assert 0 <= params.num_loci <= len(reference), (
                f"cannot generate {params.num_loci} loci for genome of length {len(reference)}"
            )
            locations = random.sample(list(range(len(reference))), params.num_loci)
            locations.sort()
            return locations

        @classmethod
        def _reference_genome(cls, params: Parameters) -> str:
            """
            Make a random reference genome.

            Args:
                params: Parameters object.

            Returns:
                String of ACGT bases.
            """

            return "".join(random.choices(list(BASES.keys()), k=params.genome_length))

        def random_genome(self, params: Parameters) -> str:
            """
            Make a random genome based on a reference genome.

            Args:
                params: Parameters object.

            Returns:
                String of ACGT bases.
            """

            genome = list(self.reference)
            for loc in self.loci:
                if random.random() < params.p_mutation:
                    genome[loc] = random.choice(BASES[genome[loc]])
            return "".join(genome)

        def _loci_to_dict(self):
            """Convert mutation loci into dictionaries for persistence."""

            return [{"ident": i + 1, "locus": locus} for i, locus in enumerate(self.loci)]

### `make(params)` `classmethod`

Construct a list containing a single species. (The result is returned in a list to be consistent with other classes' `make` methods.)

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`params` | `Parameters` | Parameters object. | required

Returns:

Type | Description
--- | ---
`list[Self]` | List containin a single `Species`.

Source code in `src/snailz/species.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
    @classmethod
    def make(cls, params: Parameters) -> list[Self]:
        """
        Construct a list containing a single species. (The result
        is returned in a list to be consistent with other classes'
        `make` methods.)

        Args:
            params: Parameters object.

        Returns:
            List containin a single `Species`.
        """
        reference = cls._reference_genome(params)
        loci = cls._random_loci(params, reference)
        susc_locus = random.choice(loci)
        susc_base = random.choice(BASES[reference[susc_locus]])
        return [
            Species(
                reference=reference,
                loci=loci,
                susc_locus=susc_locus,
                susc_base=susc_base,
            )
        ]

### `save_csv(outdir, species)` `classmethod`

Save species as CSV. `species` must be passed in a list to be consistent with other classes' `save_csv` methods. Scalar properties of the species are saved in one file; mutation loci values are pivoted to long form and saved in a separate file.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`outdir` | `Path | str` | Output directory. | required
`species` | `list[Self]` | List containing `Species` to save. | required

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

    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    @classmethod
    def save_csv(cls, outdir: Path | str, species: list[Self]):
        """
        Save species as CSV. `species` must be passed in a list to be
        consistent with other classes' `save_csv` methods. Scalar
        properties of the species are saved in one file; mutation loci
        values are pivoted to long form and saved in a separate file.

        Args:
            outdir: Output directory.
            species: List containing `Species` to save.

        """

        assert isinstance(species, list)
        super().save_csv(outdir, species)

        with open(Path(outdir, "species_loci.csv"), "w", newline="") as stream:
            objects = species[0]._loci_to_dict()
            writer = cls._csv_dict_writer(stream, list(objects[0].keys()))
            for obj in objects:
                writer.writerow(obj)

### `save_db(db, species)` `classmethod`

Save species to database. `species` must be passed in a list to be consistent with other classes' `save_csv` methods. Scalar properties of the species are saved in one table; mutation loci values are pivoted to long form and saved in a separate table.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`db` | `Database` | Database connector. | required
`species` | `list[Self]` | List containing `Species` to save. | required

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

     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    @classmethod
    def save_db(cls, db: Database, species: list[Self]):
        """
        Save species to database. `species` must be passed in a
        list to be consistent with other classes' `save_csv` methods.
        Scalar properties of the species are saved in one table;
        mutation loci values are pivoted to long form and saved in a
        separate table.

        Args:
            db: Database connector.
            species: List containing `Species` to save.
        """

        assert isinstance(species, list)
        super().save_db(db, species)
        table = db["species_loci"]
        table.insert_all(species[0]._loci_to_dict(), pk="ident")

### `random_genome(params)`

Make a random genome based on a reference genome.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`params` | `Parameters` | Parameters object. | required

Returns:

Type | Description
--- | ---
`str` | String of ACGT bases.

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

    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    def random_genome(self, params: Parameters) -> str:
        """
        Make a random genome based on a reference genome.

        Args:
            params: Parameters object.

        Returns:
            String of ACGT bases.
        """

        genome = list(self.reference)
        for loc in self.loci:
            if random.random() < params.p_mutation:
                genome[loc] = random.choice(BASES[genome[loc]])
        return "".join(genome)