rhinotype 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rhinotype-1.0.0/LICENSE +21 -0
- rhinotype-1.0.0/PKG-INFO +140 -0
- rhinotype-1.0.0/README.md +119 -0
- rhinotype-1.0.0/pyproject.toml +40 -0
- rhinotype-1.0.0/setup.cfg +4 -0
- rhinotype-1.0.0/src/rhinotype/SNPeek.py +65 -0
- rhinotype-1.0.0/src/rhinotype/__init__.py +21 -0
- rhinotype-1.0.0/src/rhinotype/assign_types.py +150 -0
- rhinotype-1.0.0/src/rhinotype/count_SNPs.py +10 -0
- rhinotype-1.0.0/src/rhinotype/data/Vp4_2_assigned_types.csv +178 -0
- rhinotype-1.0.0/src/rhinotype/data/input_aln.fasta +844 -0
- rhinotype-1.0.0/src/rhinotype/data/prototypes.csv +170 -0
- rhinotype-1.0.0/src/rhinotype/data/prototypes.fasta +338 -0
- rhinotype-1.0.0/src/rhinotype/data/test.fasta +4 -0
- rhinotype-1.0.0/src/rhinotype/data/test.translated.fasta +4 -0
- rhinotype-1.0.0/src/rhinotype/data/vp1_align.fasta +11804 -0
- rhinotype-1.0.0/src/rhinotype/data/vp1_assigned_types.csv +178 -0
- rhinotype-1.0.0/src/rhinotype/data/vp1_prototypes.fasta +2280 -0
- rhinotype-1.0.0/src/rhinotype/data/vp1_test.csv +155 -0
- rhinotype-1.0.0/src/rhinotype/data/vp1_test.fasta +29 -0
- rhinotype-1.0.0/src/rhinotype/data/vp1_test_data.fasta +3858 -0
- rhinotype-1.0.0/src/rhinotype/data/vp1_test_translated.fasta +6 -0
- rhinotype-1.0.0/src/rhinotype/distance_helpers.py +208 -0
- rhinotype-1.0.0/src/rhinotype/genetic_distances.py +241 -0
- rhinotype-1.0.0/src/rhinotype/getprototypeseqs.py +51 -0
- rhinotype-1.0.0/src/rhinotype/main.py +437 -0
- rhinotype-1.0.0/src/rhinotype/overall_mean_distance.py +148 -0
- rhinotype-1.0.0/src/rhinotype/pairwise_distances.py +49 -0
- rhinotype-1.0.0/src/rhinotype/plot_AA.py +96 -0
- rhinotype-1.0.0/src/rhinotype/plot_distances.py +34 -0
- rhinotype-1.0.0/src/rhinotype/plot_frequency.py +62 -0
- rhinotype-1.0.0/src/rhinotype/plot_tree.py +36 -0
- rhinotype-1.0.0/src/rhinotype/readfasta.py +37 -0
- rhinotype-1.0.0/src/rhinotype.egg-info/PKG-INFO +140 -0
- rhinotype-1.0.0/src/rhinotype.egg-info/SOURCES.txt +37 -0
- rhinotype-1.0.0/src/rhinotype.egg-info/dependency_links.txt +1 -0
- rhinotype-1.0.0/src/rhinotype.egg-info/entry_points.txt +2 -0
- rhinotype-1.0.0/src/rhinotype.egg-info/requires.txt +6 -0
- rhinotype-1.0.0/src/rhinotype.egg-info/top_level.txt +1 -0
rhinotype-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 omicscodeathon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
rhinotype-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rhinotype
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A python tool used to automatically genotype rhinovirus.
|
|
5
|
+
Author-email: Ephantus Wambui <ephywambui72@gmail.com>, Daniel Okoro <ugookorodaniel620@gmail.com>, Andrew Acheampong <acheampongandrews1999@gmail.com>, Parcelli Jepchirchir <parcelmaiyo@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/omicscodeathon/rhinotype
|
|
8
|
+
Keywords: bioinformatics,virology,genotyping,rhinovirus,genotype
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: matplotlib>=3.8
|
|
15
|
+
Requires-Dist: numpy>=2.3
|
|
16
|
+
Requires-Dist: pandas>=2.3
|
|
17
|
+
Requires-Dist: seaborn>=0.13
|
|
18
|
+
Requires-Dist: scipy>=1.16
|
|
19
|
+
Requires-Dist: biopython>=1.86
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# rhinotype
|
|
23
|
+
rhinotype: A Python Package for the Classification of Rhinoviruses
|
|
24
|
+
|
|
25
|
+
## Table of contents
|
|
26
|
+
|
|
27
|
+
1. [Background](#background)
|
|
28
|
+
2. [Workflow](#workflow)
|
|
29
|
+
3. [Installation](#installation)
|
|
30
|
+
4. [getprototypeseqs](#getprototypeseqs)
|
|
31
|
+
5. [readfasta](#readfasta)
|
|
32
|
+
6. [SNPeek](#snpeek)
|
|
33
|
+
7. [assign_types](#assign_types)
|
|
34
|
+
8. [pairwise_distances](#pairwise_distances)
|
|
35
|
+
9. [overall_mean_distance](#overall_mean_distance)
|
|
36
|
+
10. [count_SNPs](#count_snps)
|
|
37
|
+
11. [plot_frequency](#plot_frequency)
|
|
38
|
+
12. [plot_distances](#plot_distances)
|
|
39
|
+
13. [plot_tree](#plot_tree)
|
|
40
|
+
14. [plot_AA](#plot_aa)
|
|
41
|
+
15. [Citation](#citation)
|
|
42
|
+
16. [Contributors](#contributors)
|
|
43
|
+
|
|
44
|
+
## <a id="background"></a>Background
|
|
45
|
+
|
|
46
|
+
Among the major causes of human respiratory infections, rhinovirus causes around 50% of all the year-round cases of common cold. This virus belongs to the Enterovirus genus in the Picornaviridae family. RV-A, RV-B, and RV-C are the three species under the genus Rhinovirus, each having about 169 different genotypes. Rhinoviruses are positive-sense, non-enveloped RNA viruses with approximately 7.2 kilobases long genome. The genome codes for seven non-structural proteins and four structural proteins—VP1, VP2, VP3, and VP4—which are part of the genome encoding viral replication and host infection mechanisms. Genotyping of Rhinovirus, until now, is done manually, while an R software package, [rhinotypeR](https://github.com/omicscodeathon/rhinotypeR/tree/main), allows for fully automated genotyping based on the VP4 region. The Python rhinovirus type package brings out VP1 and VP4 regions that aim to improve acuity in genotyping. The VP1 region has been tested to display better acuity in genotypic identification, while the VP4/2 region ensures compatibility under one universal amplification protocol for rapid genotyping.
|
|
47
|
+
|
|
48
|
+
## <a id="workflow"></a>Workflow
|
|
49
|
+
|
|
50
|
+

|
|
51
|
+
|
|
52
|
+
## <a id="installation"></a>Installation
|
|
53
|
+
|
|
54
|
+
You can install the package using the following command:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
pip install rhinotype
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Note:** This package requires [MAFFT](https://mafft.cbrc.jp/alignment/software/) for sequence alignment. Please ensure that you have MAFFT installed and that it is available in your system's PATH.
|
|
61
|
+
|
|
62
|
+
#### Run the package
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
rhinotype --mode {demo,user} --region {Vp1,Vp4/2} --threshold {VALUE} [--input FILE] [--model MODEL] --threads {VALUE}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## <a id="getprototypeseqs"></a>getprotypeseqs
|
|
69
|
+
|
|
70
|
+
Gets the prototype sequences of the Rhinovirus genotypes and save the reference fasta file into RVRefs directory. Making both VP1 and VP4/2 sequences available depending on whch region you have. The tool then combines user sequences together with the prototype sequences and align them using MAFFT or any other alignment tool.
|
|
71
|
+
|
|
72
|
+
## <a id="readfasta"></a>readfasta
|
|
73
|
+
|
|
74
|
+
Reads the alignments/sequences. Compares the input sequences and pads the short sequences with - until they are long as the longest sequence. The sequences are then stored in a dictionary with the sequence name as the key and the sequence as the value.
|
|
75
|
+
|
|
76
|
+
## <a id="snpeek"></a>SNPeek
|
|
77
|
+
|
|
78
|
+
SNPeek function visualizes single nuclotide polymorphisms(SNPs) using the users sequences, relative to a specified reference sequence. To specify a reference sequence, the user should move the sequence to the bottom of the alignment. Substitutions are color coded by nucleotide: A = green, T = red, C = blue, G = yellow.
|
|
79
|
+
|
|
80
|
+
## <a id="assign_types"></a>assign_types
|
|
81
|
+
|
|
82
|
+
The ```assign_types``` function assigns genotype to the sequences in the fasta file by comparing them to the prototype sequences. The classification is based on pairwise distances calculated using a specified distance model. Users can adjust parameters for gap deletion and threshold to control the classification process. The function reads prototype sequences from predefined CSV files based on the specified prototype type.
|
|
83
|
+
|
|
84
|
+
Parameters:
|
|
85
|
+
|
|
86
|
+
- ```fasta_data``` (DataFrame): A DataFrame containing the sequences to be classified.
|
|
87
|
+
- ```model``` (str): The distance model to use (default is 'p-distance').
|
|
88
|
+
- ```gap_deletion``` (bool): Whether to apply gap deletion in distance calculations (default is True).
|
|
89
|
+
- ```threshold``` (float): The distance threshold for classification (default is 0.105)
|
|
90
|
+
|
|
91
|
+
## <a id="pairwise_distances"></a>pairwise_distances
|
|
92
|
+
|
|
93
|
+
Calculates pairwise genetic distances between sequences in a FASTA dataset using the specified distance model. The function supports various models for distance calculation and can optionally apply gap deletion. The result is a DataFrame showing the distances between each pair of sequences.
|
|
94
|
+
|
|
95
|
+
Parameters:
|
|
96
|
+
|
|
97
|
+
- ```fasta_data``` (DataFrame): A DataFrame containing the sequences to be analyzed.
|
|
98
|
+
- ```model``` (str): The distance model to use. Options include:
|
|
99
|
+
- ```"p-distance"```: Simple proportion of differing sites.
|
|
100
|
+
- ```"JC"```: Jukes-Cantor model.
|
|
101
|
+
- ```"Kimura2p"```: Kimura 2-parameter model.
|
|
102
|
+
- ```"Tamura3p"```: Tamura 3-parameter model.
|
|
103
|
+
- ```gap_deletion``` (bool): Whether to apply gap deletion in the distance calculation (default is True).
|
|
104
|
+
- ```Output```: The function returns a numpy array containing the pairwise distances between the sequences
|
|
105
|
+
|
|
106
|
+
## <a id="overall_mean_distance"></a>overall_mean_distance
|
|
107
|
+
|
|
108
|
+
Calculates the overall mean genetic distance between sequences using various distance models. The function supports multiple models and can optionally handle gap deletion in sequences. It provides an average distance value based on the chosen model.
|
|
109
|
+
|
|
110
|
+
## <a id="count_snps"></a>count_SNPs
|
|
111
|
+
|
|
112
|
+
Counts the single nucleotide polymorphisms (SNPs) in the provided sequence data and can optionally handle gap deletion in the sequences.
|
|
113
|
+
|
|
114
|
+
## <a id="plot_frequency"></a>plot_frequency
|
|
115
|
+
|
|
116
|
+
Generates a bar chart visualizing the frequency of assigned types from a DataFrame. The function creates a bar chart where each bar represents the count of a specific type, and colors are used to differentiate between species. The chart is saved as an image file and can optionally include a legend.
|
|
117
|
+
|
|
118
|
+
## <a id="plot_distances"></a>plot_distances
|
|
119
|
+
|
|
120
|
+
Generates a heatmap to visualize the pairwise genetic distances between sequences and saves the plot as an image file. The color scale represents the magnitude of genetic distances.
|
|
121
|
+
|
|
122
|
+
## <a id="plot_tree"></a>plot_tree
|
|
123
|
+
|
|
124
|
+
Generates a hierarchical clustering dendrogram from the pairwise genetic distances between sequences. The function performs complete linkage clustering and visualizes the results as a tree diagram. The dendrogram is saved as an image file.
|
|
125
|
+
|
|
126
|
+
## <a id="plot_aa"></a>plot_AA
|
|
127
|
+
|
|
128
|
+
Visualizes amino acid differences between protein sequences. The function compares each sequence to a reference sequence and plots the differences as colored bars, categorizing amino acids based on their properties. The plot is saved as an image file.
|
|
129
|
+
|
|
130
|
+
## <a id="citation"></a>Citation
|
|
131
|
+
|
|
132
|
+
## <a id="contributors"></a>Contributors
|
|
133
|
+
|
|
134
|
+
1. [Ephantus Wambui](https://github.com/Ephantus-Wambui)
|
|
135
|
+
|
|
136
|
+
2. [Daniel Okoro](https://github.com/danny6200)
|
|
137
|
+
|
|
138
|
+
3. [Andrew Acheampong](https://github.com/AcheampongAndy)
|
|
139
|
+
|
|
140
|
+
4. [Parcelli Jepchirchir](https://github.com/Parcelli)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# rhinotype
|
|
2
|
+
rhinotype: A Python Package for the Classification of Rhinoviruses
|
|
3
|
+
|
|
4
|
+
## Table of contents
|
|
5
|
+
|
|
6
|
+
1. [Background](#background)
|
|
7
|
+
2. [Workflow](#workflow)
|
|
8
|
+
3. [Installation](#installation)
|
|
9
|
+
4. [getprototypeseqs](#getprototypeseqs)
|
|
10
|
+
5. [readfasta](#readfasta)
|
|
11
|
+
6. [SNPeek](#snpeek)
|
|
12
|
+
7. [assign_types](#assign_types)
|
|
13
|
+
8. [pairwise_distances](#pairwise_distances)
|
|
14
|
+
9. [overall_mean_distance](#overall_mean_distance)
|
|
15
|
+
10. [count_SNPs](#count_snps)
|
|
16
|
+
11. [plot_frequency](#plot_frequency)
|
|
17
|
+
12. [plot_distances](#plot_distances)
|
|
18
|
+
13. [plot_tree](#plot_tree)
|
|
19
|
+
14. [plot_AA](#plot_aa)
|
|
20
|
+
15. [Citation](#citation)
|
|
21
|
+
16. [Contributors](#contributors)
|
|
22
|
+
|
|
23
|
+
## <a id="background"></a>Background
|
|
24
|
+
|
|
25
|
+
Among the major causes of human respiratory infections, rhinovirus causes around 50% of all the year-round cases of common cold. This virus belongs to the Enterovirus genus in the Picornaviridae family. RV-A, RV-B, and RV-C are the three species under the genus Rhinovirus, each having about 169 different genotypes. Rhinoviruses are positive-sense, non-enveloped RNA viruses with approximately 7.2 kilobases long genome. The genome codes for seven non-structural proteins and four structural proteins—VP1, VP2, VP3, and VP4—which are part of the genome encoding viral replication and host infection mechanisms. Genotyping of Rhinovirus, until now, is done manually, while an R software package, [rhinotypeR](https://github.com/omicscodeathon/rhinotypeR/tree/main), allows for fully automated genotyping based on the VP4 region. The Python rhinovirus type package brings out VP1 and VP4 regions that aim to improve acuity in genotyping. The VP1 region has been tested to display better acuity in genotypic identification, while the VP4/2 region ensures compatibility under one universal amplification protocol for rapid genotyping.
|
|
26
|
+
|
|
27
|
+
## <a id="workflow"></a>Workflow
|
|
28
|
+
|
|
29
|
+

|
|
30
|
+
|
|
31
|
+
## <a id="installation"></a>Installation
|
|
32
|
+
|
|
33
|
+
You can install the package using the following command:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
pip install rhinotype
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Note:** This package requires [MAFFT](https://mafft.cbrc.jp/alignment/software/) for sequence alignment. Please ensure that you have MAFFT installed and that it is available in your system's PATH.
|
|
40
|
+
|
|
41
|
+
#### Run the package
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
rhinotype --mode {demo,user} --region {Vp1,Vp4/2} --threshold {VALUE} [--input FILE] [--model MODEL] --threads {VALUE}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## <a id="getprototypeseqs"></a>getprotypeseqs
|
|
48
|
+
|
|
49
|
+
Gets the prototype sequences of the Rhinovirus genotypes and save the reference fasta file into RVRefs directory. Making both VP1 and VP4/2 sequences available depending on whch region you have. The tool then combines user sequences together with the prototype sequences and align them using MAFFT or any other alignment tool.
|
|
50
|
+
|
|
51
|
+
## <a id="readfasta"></a>readfasta
|
|
52
|
+
|
|
53
|
+
Reads the alignments/sequences. Compares the input sequences and pads the short sequences with - until they are long as the longest sequence. The sequences are then stored in a dictionary with the sequence name as the key and the sequence as the value.
|
|
54
|
+
|
|
55
|
+
## <a id="snpeek"></a>SNPeek
|
|
56
|
+
|
|
57
|
+
SNPeek function visualizes single nuclotide polymorphisms(SNPs) using the users sequences, relative to a specified reference sequence. To specify a reference sequence, the user should move the sequence to the bottom of the alignment. Substitutions are color coded by nucleotide: A = green, T = red, C = blue, G = yellow.
|
|
58
|
+
|
|
59
|
+
## <a id="assign_types"></a>assign_types
|
|
60
|
+
|
|
61
|
+
The ```assign_types``` function assigns genotype to the sequences in the fasta file by comparing them to the prototype sequences. The classification is based on pairwise distances calculated using a specified distance model. Users can adjust parameters for gap deletion and threshold to control the classification process. The function reads prototype sequences from predefined CSV files based on the specified prototype type.
|
|
62
|
+
|
|
63
|
+
Parameters:
|
|
64
|
+
|
|
65
|
+
- ```fasta_data``` (DataFrame): A DataFrame containing the sequences to be classified.
|
|
66
|
+
- ```model``` (str): The distance model to use (default is 'p-distance').
|
|
67
|
+
- ```gap_deletion``` (bool): Whether to apply gap deletion in distance calculations (default is True).
|
|
68
|
+
- ```threshold``` (float): The distance threshold for classification (default is 0.105)
|
|
69
|
+
|
|
70
|
+
## <a id="pairwise_distances"></a>pairwise_distances
|
|
71
|
+
|
|
72
|
+
Calculates pairwise genetic distances between sequences in a FASTA dataset using the specified distance model. The function supports various models for distance calculation and can optionally apply gap deletion. The result is a DataFrame showing the distances between each pair of sequences.
|
|
73
|
+
|
|
74
|
+
Parameters:
|
|
75
|
+
|
|
76
|
+
- ```fasta_data``` (DataFrame): A DataFrame containing the sequences to be analyzed.
|
|
77
|
+
- ```model``` (str): The distance model to use. Options include:
|
|
78
|
+
- ```"p-distance"```: Simple proportion of differing sites.
|
|
79
|
+
- ```"JC"```: Jukes-Cantor model.
|
|
80
|
+
- ```"Kimura2p"```: Kimura 2-parameter model.
|
|
81
|
+
- ```"Tamura3p"```: Tamura 3-parameter model.
|
|
82
|
+
- ```gap_deletion``` (bool): Whether to apply gap deletion in the distance calculation (default is True).
|
|
83
|
+
- ```Output```: The function returns a numpy array containing the pairwise distances between the sequences
|
|
84
|
+
|
|
85
|
+
## <a id="overall_mean_distance"></a>overall_mean_distance
|
|
86
|
+
|
|
87
|
+
Calculates the overall mean genetic distance between sequences using various distance models. The function supports multiple models and can optionally handle gap deletion in sequences. It provides an average distance value based on the chosen model.
|
|
88
|
+
|
|
89
|
+
## <a id="count_snps"></a>count_SNPs
|
|
90
|
+
|
|
91
|
+
Counts the single nucleotide polymorphisms (SNPs) in the provided sequence data and can optionally handle gap deletion in the sequences.
|
|
92
|
+
|
|
93
|
+
## <a id="plot_frequency"></a>plot_frequency
|
|
94
|
+
|
|
95
|
+
Generates a bar chart visualizing the frequency of assigned types from a DataFrame. The function creates a bar chart where each bar represents the count of a specific type, and colors are used to differentiate between species. The chart is saved as an image file and can optionally include a legend.
|
|
96
|
+
|
|
97
|
+
## <a id="plot_distances"></a>plot_distances
|
|
98
|
+
|
|
99
|
+
Generates a heatmap to visualize the pairwise genetic distances between sequences and saves the plot as an image file. The color scale represents the magnitude of genetic distances.
|
|
100
|
+
|
|
101
|
+
## <a id="plot_tree"></a>plot_tree
|
|
102
|
+
|
|
103
|
+
Generates a hierarchical clustering dendrogram from the pairwise genetic distances between sequences. The function performs complete linkage clustering and visualizes the results as a tree diagram. The dendrogram is saved as an image file.
|
|
104
|
+
|
|
105
|
+
## <a id="plot_aa"></a>plot_AA
|
|
106
|
+
|
|
107
|
+
Visualizes amino acid differences between protein sequences. The function compares each sequence to a reference sequence and plots the differences as colored bars, categorizing amino acids based on their properties. The plot is saved as an image file.
|
|
108
|
+
|
|
109
|
+
## <a id="citation"></a>Citation
|
|
110
|
+
|
|
111
|
+
## <a id="contributors"></a>Contributors
|
|
112
|
+
|
|
113
|
+
1. [Ephantus Wambui](https://github.com/Ephantus-Wambui)
|
|
114
|
+
|
|
115
|
+
2. [Daniel Okoro](https://github.com/danny6200)
|
|
116
|
+
|
|
117
|
+
3. [Andrew Acheampong](https://github.com/AcheampongAndy)
|
|
118
|
+
|
|
119
|
+
4. [Parcelli Jepchirchir](https://github.com/Parcelli)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=45", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "rhinotype"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "A python tool used to automatically genotype rhinovirus."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
authors = [
|
|
12
|
+
{name = "Ephantus Wambui", email = "ephywambui72@gmail.com"},
|
|
13
|
+
{name = "Daniel Okoro", email = "ugookorodaniel620@gmail.com"},
|
|
14
|
+
{name = "Andrew Acheampong", email = "acheampongandrews1999@gmail.com"},
|
|
15
|
+
{name = "Parcelli Jepchirchir", email = "parcelmaiyo@gmail.com"}
|
|
16
|
+
]
|
|
17
|
+
license = {text = "MIT"}
|
|
18
|
+
keywords = ["bioinformatics", "virology", "genotyping", "rhinovirus", "genotype"]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
dependencies = [
|
|
25
|
+
"matplotlib >= 3.8",
|
|
26
|
+
"numpy >= 2.3",
|
|
27
|
+
"pandas >= 2.3",
|
|
28
|
+
"seaborn >= 0.13",
|
|
29
|
+
"scipy >= 1.16",
|
|
30
|
+
"biopython >= 1.86"
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Homepage = "https://github.com/omicscodeathon/rhinotype"
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
rhinotype = "rhinotype.main:main"
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.package-data]
|
|
40
|
+
rhinotype = ["data/*.fasta", "data/*.csv"]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from Bio import SeqIO
|
|
4
|
+
import matplotlib.pyplot as plt
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
# --- FASTA Reading Function ---
|
|
8
|
+
def read_fasta(fasta_file):
|
|
9
|
+
sequences = []
|
|
10
|
+
headers = []
|
|
11
|
+
for record in SeqIO.parse(fasta_file, "fasta"):
|
|
12
|
+
sequences.append(str(record.seq))
|
|
13
|
+
headers.append(record.id)
|
|
14
|
+
return {"sequences": sequences, "headers": headers}
|
|
15
|
+
|
|
16
|
+
# --- Sequence Comparison Function ---
|
|
17
|
+
def compare_sequences(seqA, seqB):
|
|
18
|
+
differences = [i for i in range(len(seqA)) if seqA[i] != seqB[i]]
|
|
19
|
+
subsType = [seqB[i] for i in differences]
|
|
20
|
+
return pd.DataFrame({"position": differences, "subsType": subsType})
|
|
21
|
+
|
|
22
|
+
# --- SNPeek Plotting Function ---
|
|
23
|
+
def SNPeek(fastaData, region="Unknown", output_dir=None, showLegend=False):
|
|
24
|
+
sequences = fastaData["sequences"]
|
|
25
|
+
seqNames = fastaData["headers"]
|
|
26
|
+
genomeLength = max([len(seq) for seq in sequences])
|
|
27
|
+
|
|
28
|
+
# Define color map for nucleotide substitutions
|
|
29
|
+
colorMap = {"A": "green", "T": "red", "C": "blue", "G": "yellow"}
|
|
30
|
+
|
|
31
|
+
diffList = []
|
|
32
|
+
for i in range(1, len(sequences)):
|
|
33
|
+
diff = compare_sequences(sequences[0], sequences[i])
|
|
34
|
+
diff["color"] = diff["subsType"].map(colorMap).fillna("black")
|
|
35
|
+
diffList.append(diff)
|
|
36
|
+
|
|
37
|
+
plt.figure(figsize=(15, 10))
|
|
38
|
+
plt.xlim(1, genomeLength)
|
|
39
|
+
plt.ylim(0.5, len(sequences))
|
|
40
|
+
plt.xlabel(f"Genome Position (reference: {seqNames[-1]})", fontsize=10)
|
|
41
|
+
plt.yticks(ticks=np.arange(1, len(sequences) + 1), labels=seqNames, fontsize=10)
|
|
42
|
+
plt.gca().yaxis.set_tick_params(labelsize=8)
|
|
43
|
+
plt.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1)
|
|
44
|
+
|
|
45
|
+
for i, diff in enumerate(diffList, start=1):
|
|
46
|
+
for _, row in diff.iterrows():
|
|
47
|
+
plt.plot([row["position"], row["position"]], [i - 0.25, i + 0.25], color=row["color"], marker="|")
|
|
48
|
+
|
|
49
|
+
if showLegend:
|
|
50
|
+
plt.legend(["A", "T", "C", "G", "Other"],
|
|
51
|
+
handlelength=0.8, markerfirst=False,
|
|
52
|
+
loc="upper left", bbox_to_anchor=(1, 1),
|
|
53
|
+
facecolor="white", framealpha=0.7)
|
|
54
|
+
|
|
55
|
+
plt.title(f"{region} Nucleotide Differences from Reference Sequence")
|
|
56
|
+
|
|
57
|
+
if output_dir is None:
|
|
58
|
+
output_dir = os.path.join(os.getcwd(), "figures")
|
|
59
|
+
|
|
60
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
61
|
+
save_path = os.path.join(output_dir, "SNPeek.png")
|
|
62
|
+
plt.savefig(save_path)
|
|
63
|
+
# plt.show()
|
|
64
|
+
|
|
65
|
+
print(f"Figure saved at: {save_path}")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from importlib import metadata as _metadata
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
rhinotype package top-level.
|
|
5
|
+
|
|
6
|
+
Provides a robust way to expose the package version without importing
|
|
7
|
+
submodules at package import time.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def _get_version():
|
|
11
|
+
try:
|
|
12
|
+
return _metadata.version("rhinotype")
|
|
13
|
+
except Exception:
|
|
14
|
+
# Fall back to a safe default if package metadata isn't available
|
|
15
|
+
return "0.0.0"
|
|
16
|
+
|
|
17
|
+
__all__ = ["__version__"]
|
|
18
|
+
__version__ = _get_version()
|
|
19
|
+
|
|
20
|
+
# Clean up names from the package namespace
|
|
21
|
+
del _get_version, _metadata
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import numpy as np
|
|
4
|
+
import datetime
|
|
5
|
+
from .pairwise_distances import pairwise_distances
|
|
6
|
+
import importlib.resources
|
|
7
|
+
|
|
8
|
+
def assign_types(fasta_data, user_input, model='p-distance', gap_deletion=True, threshold=0.405,
|
|
9
|
+
save_report=True, output_dir='reports', user_seq_names=None, distances_matrix=None):
|
|
10
|
+
"""
|
|
11
|
+
Assigns types to query sequences based on p-distance to known prototypes.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
fasta_data (pd.DataFrame): DataFrame from pairwise_distances input.
|
|
15
|
+
model (str): Distance model (default 'p-distance').
|
|
16
|
+
gap_deletion (bool): Whether to delete gaps (default True).
|
|
17
|
+
threshold (float): Max p-distance for assignment (default 0.105).
|
|
18
|
+
save_report (bool): If True, saves the output DataFrame to a CSV file.
|
|
19
|
+
output_dir (str): Directory to save the report (default 'reports').
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
pd.DataFrame: A DataFrame with query, assignedType, distance, and reference.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# Read prototype sequences
|
|
26
|
+
try:
|
|
27
|
+
# Determine the correct prototype CSV file
|
|
28
|
+
user_input_cap = user_input.capitalize()
|
|
29
|
+
if user_input_cap == 'Vp1':
|
|
30
|
+
prototype_filename = 'vp1_test.csv'
|
|
31
|
+
elif user_input_cap == 'Vp4/2':
|
|
32
|
+
prototype_filename = 'prototypes.csv'
|
|
33
|
+
else:
|
|
34
|
+
raise ValueError("Invalid input. Please specify either 'Vp1' or 'Vp4/2'.")
|
|
35
|
+
|
|
36
|
+
# Use importlib.resources to access the data file
|
|
37
|
+
path_obj = importlib.resources.files('rhinotype.data').joinpath(prototype_filename)
|
|
38
|
+
with importlib.resources.as_file(path_obj) as path:
|
|
39
|
+
prototypes_df = pd.read_csv(path)
|
|
40
|
+
|
|
41
|
+
except FileNotFoundError:
|
|
42
|
+
raise Exception("Error: Failed during genotype assignment. Prototypes file not found. Please check the file path.")
|
|
43
|
+
|
|
44
|
+
names_to_keep = prototypes_df['Accession'].tolist()
|
|
45
|
+
|
|
46
|
+
# Run pairwiseDistances to calculate distances
|
|
47
|
+
if distances_matrix is not None:
|
|
48
|
+
print("Using pre-calculated distance matrix.")
|
|
49
|
+
distances = distances_matrix.copy() # Use the provided matrix
|
|
50
|
+
else:
|
|
51
|
+
print("Calculating pairwise distances for assign_types...")
|
|
52
|
+
# Run pairwiseDistances to calculate distances
|
|
53
|
+
distances = pairwise_distances(fasta_data, model=model, gap_deletion=gap_deletion)
|
|
54
|
+
|
|
55
|
+
# Filter columns based on the prototypes
|
|
56
|
+
distances = distances.loc[:, distances.columns.isin(names_to_keep)]
|
|
57
|
+
|
|
58
|
+
if user_seq_names is not None:
|
|
59
|
+
# We *only* want to classify the user's sequences.
|
|
60
|
+
print(f"Attempting to filter for {len(user_seq_names)} user-provided sequence names...")
|
|
61
|
+
|
|
62
|
+
# Get all valid names from the distance matrix (i.e., not prototypes)
|
|
63
|
+
all_mafft_names = [
|
|
64
|
+
idx_name for idx_name in distances.index
|
|
65
|
+
if idx_name not in names_to_keep
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
names_to_classify = []
|
|
69
|
+
|
|
70
|
+
# Loop through each of the user's original names
|
|
71
|
+
for original_name in user_seq_names:
|
|
72
|
+
found_match = False
|
|
73
|
+
# Loop through all the (potentially truncated) names from the MAFFT alignment
|
|
74
|
+
for mafft_name in all_mafft_names:
|
|
75
|
+
# Check if the MAFFT name *starts with* the user's original name
|
|
76
|
+
if mafft_name.startswith(original_name):
|
|
77
|
+
names_to_classify.append(mafft_name)
|
|
78
|
+
found_match = True
|
|
79
|
+
break # Found a match, go to the next original_name
|
|
80
|
+
|
|
81
|
+
if not found_match:
|
|
82
|
+
print(f"Warning: Could not find a match for original name: {original_name}")
|
|
83
|
+
|
|
84
|
+
distances = distances.loc[names_to_classify, :]
|
|
85
|
+
print(f"Report filtered for {len(names_to_classify)} user-provided sequences.")
|
|
86
|
+
|
|
87
|
+
else:
|
|
88
|
+
# Fallback to old behavior if user_seq_names is not provided
|
|
89
|
+
print("Warning: No user_seq_names provided. Classifying all non-prototypes.")
|
|
90
|
+
distances = distances.loc[~distances.index.isin(names_to_keep), :]
|
|
91
|
+
|
|
92
|
+
# Initialize lists to store output data
|
|
93
|
+
query_vec = []
|
|
94
|
+
assigned_type_vec = []
|
|
95
|
+
distance_vec = []
|
|
96
|
+
ref_seq_vec = []
|
|
97
|
+
|
|
98
|
+
# Iterate over each row (query) in the distances DataFrame
|
|
99
|
+
for i, row in distances.iterrows():
|
|
100
|
+
query_header = i
|
|
101
|
+
valid_cols = row[row < threshold].index
|
|
102
|
+
|
|
103
|
+
if len(valid_cols) == 0:
|
|
104
|
+
# If no valid columns found, mark as "unassigned"
|
|
105
|
+
assigned_type_vec.append("unassigned")
|
|
106
|
+
distance_vec.append(np.nan)
|
|
107
|
+
# Find the column with the minimum distance
|
|
108
|
+
min_dist_col = row.idxmin()
|
|
109
|
+
ref_seq_vec.append(min_dist_col)
|
|
110
|
+
else:
|
|
111
|
+
# Choose the one with the minimum distance
|
|
112
|
+
min_distance_col = row[valid_cols].idxmin()
|
|
113
|
+
assigned_type = min_distance_col
|
|
114
|
+
assigned_type_vec.append(assigned_type.replace("RV", "").split("_")[-1])
|
|
115
|
+
distance_vec.append(row[min_distance_col])
|
|
116
|
+
ref_seq_vec.append(assigned_type)
|
|
117
|
+
|
|
118
|
+
query_vec.append(query_header)
|
|
119
|
+
|
|
120
|
+
# Create a DataFrame from the results
|
|
121
|
+
output_df = pd.DataFrame({
|
|
122
|
+
'query': query_vec,
|
|
123
|
+
'assignedType': assigned_type_vec,
|
|
124
|
+
'distance': distance_vec,
|
|
125
|
+
'reference': ref_seq_vec
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
# --- Save Report ---
|
|
129
|
+
if save_report:
|
|
130
|
+
try:
|
|
131
|
+
# Create the output directory if it doesn't exist
|
|
132
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
133
|
+
# Sanitize the region name for the filename (replaces '/' with '_')
|
|
134
|
+
region_name = user_input.capitalize().replace('/', '_')
|
|
135
|
+
# Create a timestamp
|
|
136
|
+
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
137
|
+
# Define the filename
|
|
138
|
+
filename = f"classification_report_{region_name}_{timestamp}.csv"
|
|
139
|
+
# Define the full save path
|
|
140
|
+
save_path = os.path.join(output_dir, filename)
|
|
141
|
+
# Save the DataFrame to a CSV file
|
|
142
|
+
output_df.to_csv(save_path, index=False)
|
|
143
|
+
print(f"Classification report successfully saved to: {save_path}")
|
|
144
|
+
except Exception as e:
|
|
145
|
+
print(f"Error saving report: {e}")
|
|
146
|
+
|
|
147
|
+
return output_df
|
|
148
|
+
|
|
149
|
+
if __name__ == "__main__":
|
|
150
|
+
assign_types()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from .genetic_distances import count_snps_helper
|
|
2
|
+
|
|
3
|
+
def count_snp(fasta_data, gap_deletion=True):
|
|
4
|
+
# run countSNP function
|
|
5
|
+
snps = count_snps_helper(fasta_data, gap_deletion=gap_deletion)
|
|
6
|
+
# output
|
|
7
|
+
return snps
|
|
8
|
+
|
|
9
|
+
if __name__ == "__main__":
|
|
10
|
+
count_snp()
|