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.
Files changed (39) hide show
  1. rhinotype-1.0.0/LICENSE +21 -0
  2. rhinotype-1.0.0/PKG-INFO +140 -0
  3. rhinotype-1.0.0/README.md +119 -0
  4. rhinotype-1.0.0/pyproject.toml +40 -0
  5. rhinotype-1.0.0/setup.cfg +4 -0
  6. rhinotype-1.0.0/src/rhinotype/SNPeek.py +65 -0
  7. rhinotype-1.0.0/src/rhinotype/__init__.py +21 -0
  8. rhinotype-1.0.0/src/rhinotype/assign_types.py +150 -0
  9. rhinotype-1.0.0/src/rhinotype/count_SNPs.py +10 -0
  10. rhinotype-1.0.0/src/rhinotype/data/Vp4_2_assigned_types.csv +178 -0
  11. rhinotype-1.0.0/src/rhinotype/data/input_aln.fasta +844 -0
  12. rhinotype-1.0.0/src/rhinotype/data/prototypes.csv +170 -0
  13. rhinotype-1.0.0/src/rhinotype/data/prototypes.fasta +338 -0
  14. rhinotype-1.0.0/src/rhinotype/data/test.fasta +4 -0
  15. rhinotype-1.0.0/src/rhinotype/data/test.translated.fasta +4 -0
  16. rhinotype-1.0.0/src/rhinotype/data/vp1_align.fasta +11804 -0
  17. rhinotype-1.0.0/src/rhinotype/data/vp1_assigned_types.csv +178 -0
  18. rhinotype-1.0.0/src/rhinotype/data/vp1_prototypes.fasta +2280 -0
  19. rhinotype-1.0.0/src/rhinotype/data/vp1_test.csv +155 -0
  20. rhinotype-1.0.0/src/rhinotype/data/vp1_test.fasta +29 -0
  21. rhinotype-1.0.0/src/rhinotype/data/vp1_test_data.fasta +3858 -0
  22. rhinotype-1.0.0/src/rhinotype/data/vp1_test_translated.fasta +6 -0
  23. rhinotype-1.0.0/src/rhinotype/distance_helpers.py +208 -0
  24. rhinotype-1.0.0/src/rhinotype/genetic_distances.py +241 -0
  25. rhinotype-1.0.0/src/rhinotype/getprototypeseqs.py +51 -0
  26. rhinotype-1.0.0/src/rhinotype/main.py +437 -0
  27. rhinotype-1.0.0/src/rhinotype/overall_mean_distance.py +148 -0
  28. rhinotype-1.0.0/src/rhinotype/pairwise_distances.py +49 -0
  29. rhinotype-1.0.0/src/rhinotype/plot_AA.py +96 -0
  30. rhinotype-1.0.0/src/rhinotype/plot_distances.py +34 -0
  31. rhinotype-1.0.0/src/rhinotype/plot_frequency.py +62 -0
  32. rhinotype-1.0.0/src/rhinotype/plot_tree.py +36 -0
  33. rhinotype-1.0.0/src/rhinotype/readfasta.py +37 -0
  34. rhinotype-1.0.0/src/rhinotype.egg-info/PKG-INFO +140 -0
  35. rhinotype-1.0.0/src/rhinotype.egg-info/SOURCES.txt +37 -0
  36. rhinotype-1.0.0/src/rhinotype.egg-info/dependency_links.txt +1 -0
  37. rhinotype-1.0.0/src/rhinotype.egg-info/entry_points.txt +2 -0
  38. rhinotype-1.0.0/src/rhinotype.egg-info/requires.txt +6 -0
  39. rhinotype-1.0.0/src/rhinotype.egg-info/top_level.txt +1 -0
@@ -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.
@@ -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
+ ![Workflow](figures/rhinotype%20workflow.svg)
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
+ ![Workflow](figures/rhinotype%20workflow.svg)
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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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()