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
164
165
166
167
168
169
170
@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"}

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

    @classmethod
    def make(cls, params: Parameters) -> list["Species"]:
        """
        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, objects: list):
        """
        Save species as CSV. `objects` 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.
            objects: List containing `Species` to save.

        """

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

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

    @classmethod
    def save_db(cls, db: Database, objects: list):
        """
        Save species to database. `objects` 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.
            objects: List containing `Species` to save.
        """

        assert isinstance(objects, list)
        super().save_db(db, objects)
        table = db["species_loci"]
        table.insert_all(  # type: ignore[possibly-missing-attribute]
            objects[0]._loci_to_dict(), pk="ident"
        )

    @classmethod
    def table_name(cls) -> str:
        """Database table name."""

        return "species"

    @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[Species]

List containin a single Species.

Source code in src/snailz/species.py
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
@classmethod
def make(cls, params: Parameters) -> list["Species"]:
    """
    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, objects) classmethod

Save species as CSV. objects 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
objects list

List containing Species to save.

required
Source code in src/snailz/species.py
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
@classmethod
def save_csv(cls, outdir: Path | str, objects: list):
    """
    Save species as CSV. `objects` 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.
        objects: List containing `Species` to save.

    """

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

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

save_db(db, objects) classmethod

Save species to database. objects 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
objects list

List containing Species to save.

required
Source code in src/snailz/species.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
@classmethod
def save_db(cls, db: Database, objects: list):
    """
    Save species to database. `objects` 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.
        objects: List containing `Species` to save.
    """

    assert isinstance(objects, list)
    super().save_db(db, objects)
    table = db["species_loci"]
    table.insert_all(  # type: ignore[possibly-missing-attribute]
        objects[0]._loci_to_dict(), pk="ident"
    )

table_name() classmethod

Database table name.

Source code in src/snailz/species.py
110
111
112
113
114
@classmethod
def table_name(cls) -> str:
    """Database table name."""

    return "species"

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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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)