Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
members = [
"microBioRust",
"heatmap",
"seqmetrics"]
"seqmetrics", "phylo"]
resolver = "2"

[profile.dev]
Expand Down
6 changes: 6 additions & 0 deletions microBioRust/cleaned_dna.fasta
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
>seq1
ATGC-ATGCATGCATGC
>seq2
ATGCAATGCTTGCATGC
>seq3
TTGCAATCCATGCAAGC
104 changes: 104 additions & 0 deletions microBioRust/new_output_embl.gbk
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
LOCUS source_1 928 bp DNA linear CON 20-OCT-2026
DEFINITION Escherichia coli K-12 substr. MG1655.
ACCESSION source_1
KEYWORDS .
SOURCE Escherichia coli K-12 substr. MG1655
ORGANISM Escherichia coli K-12 substr. MG1655
FEATURES Location/Qualifiers
source 1..910
/organism="K-12 substr. MG1655"
/mol_type="DNA"
/strain="K-12 substr. MG1655"
/db_xref="PRJNA57779"
gene complement(1..354)
/locus_tag="b3304"
CDS complement(1..354)
/locus_tag="b3304"
/codon_start="1"
/gene="rplR"
/translation="MDKKSARIRRATRARRKLQELGATRLVVHRTPRHIYAQVIAPNGS
LVAASTVEKAIAEQLKYTGNKDAAAAVGKAVAERALEKGIKDVSFDRSGFQYHGRVQAL
DAAREAGLQ"
/product="50S ribosomal subunit protein L18"
gene complement(364..897)
/locus_tag="b3305"
CDS complement(364..897)
/locus_tag="b3305"
/codon_start="1"
/gene="rplF"
/translation="MSRVAKAPVVVPAGVDVKINGQVITIKGKNGELTRTLNDAVEVKH
NTLTFGPRDGYADGWAQAGTARALLNSMVIGVTEGFTKKLQLVGVGYRAAVKGNVINLS
GFSHPVDHQLPAGITAECPTQTEIVLKGADKQVIGQVAADLRAYRRPEPYKGKGVRYAD
VVRTKEAKK"
/product="50S ribosomal subunit protein L6"
ORIGIN
1 acctctacct tagaactgaa ggccagcttc acgggcagca tctgccagtg cctggacacg
61 accatgatat tggaacccgg aacggtcaaa ggatacatct ttgatgcctt tttccagagc
121 gcgttcagcg acagctttac ccacagctgc agccgcgtct ttgttaccgg tgtacttcag
181 ttgttcagcg atagcttttt ctacagtaga agcagctacc agaacttcag aaccgttcgg
241 tgcaattacc tgtgcgtaaa tgtgacgcgg ggtacgatgt accaccaggc gagttgcgcc
301 cagctcctgg agcttgcggc gtgcgcgggt cgcacgacgg atacgagcag atttcttatc
361 catagtgtta ccttacttct tcttagcctc tttggtacgc acgacttcgt cggcgtaacg
421 aacacccttg cctttataag gctcaggacg acggtaggcg cgcagatccg ctgcaacctg
481 gccgatcacc tgcttatcag cgcctttcag cacgatttca gtctgagtcg gacattcagc
541 agtgataccc gcaggcagct gatggtcaac aggatgagag aaacccagag acaggttaat
601 cacattgcct ttaaccgctg cacggtaacc tacaccaacc agctgcagct tcttagtgaa
661 gccttcggta acaccgataa ccattgagtt cagcagggca cgcgcggtac cagcctgtgc
721 ccaaccgtct gcgtaaccat cacgcggacc gaaggtcagg gtattatctg catgtttaac
781 ttcaacagca tcgttgagag tacgagtcag ctcgccgttt ttacctttga tcgtaataac
841 ctgaccgttg atttttacgt caacgccggc aggaacaacg accggtgctt tagcaacacg
901 agacattttt tcc

//
LOCUS source_1 928 bp DNA linear CON 20-OCT-2026
DEFINITION Escherichia coli K-12 substr. MG1655.
ACCESSION source_1
KEYWORDS .
SOURCE Escherichia coli K-12 substr. MG1655
ORGANISM Escherichia coli K-12 substr. MG1655
FEATURES Location/Qualifiers
source 1..910
/organism="K-12 substr. MG1655"
/mol_type="DNA"
/strain="K-12 substr. MG1655"
/db_xref="PRJNA57779"
gene complement(1..354)
/locus_tag="b3304"
CDS complement(1..354)
/locus_tag="b3304"
/codon_start="1"
/gene="rplR"
/translation="MDKKSARIRRATRARRKLQELGATRLVVHRTPRHIYAQVIAPNGS
LVAASTVEKAIAEQLKYTGNKDAAAAVGKAVAERALEKGIKDVSFDRSGFQYHGRVQAL
DAAREAGLQ"
/product="50S ribosomal subunit protein L18"
gene complement(364..897)
/locus_tag="b3305"
CDS complement(364..897)
/locus_tag="b3305"
/codon_start="1"
/gene="rplF"
/translation="MSRVAKAPVVVPAGVDVKINGQVITIKGKNGELTRTLNDAVEVKH
NTLTFGPRDGYADGWAQAGTARALLNSMVIGVTEGFTKKLQLVGVGYRAAVKGNVINLS
GFSHPVDHQLPAGITAECPTQTEIVLKGADKQVIGQVAADLRAYRRPEPYKGKGVRYAD
VVRTKEAKK"
/product="50S ribosomal subunit protein L6"
ORIGIN
1 acctctacct tagaactgaa ggccagcttc acgggcagca tctgccagtg cctggacacg
61 accatgatat tggaacccgg aacggtcaaa ggatacatct ttgatgcctt tttccagagc
121 gcgttcagcg acagctttac ccacagctgc agccgcgtct ttgttaccgg tgtacttcag
181 ttgttcagcg atagcttttt ctacagtaga agcagctacc agaacttcag aaccgttcgg
241 tgcaattacc tgtgcgtaaa tgtgacgcgg ggtacgatgt accaccaggc gagttgcgcc
301 cagctcctgg agcttgcggc gtgcgcgggt cgcacgacgg atacgagcag atttcttatc
361 catagtgtta ccttacttct tcttagcctc tttggtacgc acgacttcgt cggcgtaacg
421 aacacccttg cctttataag gctcaggacg acggtaggcg cgcagatccg ctgcaacctg
481 gccgatcacc tgcttatcag cgcctttcag cacgatttca gtctgagtcg gacattcagc
541 agtgataccc gcaggcagct gatggtcaac aggatgagag aaacccagag acaggttaat
601 cacattgcct ttaaccgctg cacggtaacc tacaccaacc agctgcagct tcttagtgaa
661 gccttcggta acaccgataa ccattgagtt cagcagggca cgcgcggtac cagcctgtgc
721 ccaaccgtct gcgtaaccat cacgcggacc gaaggtcagg gtattatctg catgtttaac
781 ttcaacagca tcgttgagag tacgagtcag ctcgccgttt ttacctttga tcgtaataac
841 ctgaccgttg atttttacgt caacgccggc aggaacaacg accggtgctt tagcaacacg
901 agacattttt tcc

//
20 changes: 20 additions & 0 deletions phylo/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "microBioRust-phylo"
license = "MIT"
keywords = ["bioinformatics","micro","bio","genomics","sequence-analysis"]
description = "Microbiology friendly bioinformatics Rust functions"
categories = ["science::bioinformatics::sequence-analysis", "science::bioinformatics::genomics", "science::bioinformatics","visualization","data-structures"]
readme = "README.md"
exclude = [".git",".gitignore"]
repository = "https://github.com/LCrossman/microBioRust"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[package.metadata.wasm-pack.profile.release]
opt-level = "z"

[dependencies]
phylo = "6.0.0"
11 changes: 11 additions & 0 deletions phylo/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*!
The aim of this crate is to provide Microbiology friendly Rust functions for bioinformatics.

With phylo module you should be able to

1. Parse newick trees into Rust equivalent data structure
2. Conversion of newick tree format to other file formats like phyloXML
3. Neighbor joining, bootstrapping from many files, visualizing, rooting etc.
*/
#![allow(non_snake_case)]
pub mod parser;
126 changes: 126 additions & 0 deletions phylo/src/parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use std::io::{BufRead, Error, ErrorKind};

use phylo::prelude::*;

struct Scanner<R: BufRead> {
col: usize,
line: usize,
reader: R,
scratch: Vec<u8>,
}

impl<R: BufRead> Scanner<R> {
fn new(reader: R) -> Self {
Self {
reader,
line: 1,
col: 0,
scratch: vec![],
}
}
}

impl<R: BufRead> Iterator for Scanner<R> {
type Item = std::io::Result<Vec<u8>>;

fn next(&mut self) -> Option<Self::Item> {
loop {
let buffer = self.reader.fill_buf().ok()?;
let mut consumed_amt = 0;
let mut flush = false;
let buffer_len = buffer.len();

if buffer.is_empty() {
if self.scratch.is_empty() {
return None; // reached EOF without any issues
} else {
return Some(Err(Error::new(
ErrorKind::InvalidData,
format!(
"Incomplete newick tree found at line: {}, col:{}",
self.line, self.col
),
)));
}
}

while consumed_amt < buffer_len {
let b = buffer[consumed_amt];
consumed_amt += 1;

if b == b'\n' {
self.line += 1;
self.col = 0;
} else {
self.col += 1;
}

if b.is_ascii_whitespace() {
continue;
}
self.scratch.push(b);
if b == b';' {
flush = true;
break;
}
}
self.reader.consume(consumed_amt);
if flush {
return Some(Ok(std::mem::take(&mut self.scratch)));
}
}
}
}

struct PhyloParser<R: BufRead> {
scanner: Scanner<R>,
}

impl<R: BufRead> PhyloParser<R> {
fn new(scanner: Scanner<R>) -> Self {
Self { scanner }
}
}

impl<R: BufRead> Iterator for PhyloParser<R> {
type Item = std::io::Result<PhyloTree>;

fn next(&mut self) -> Option<Self::Item> {
let bytes = match self.scanner.next()? {
Ok(b) => b,
Err(e) => return Some(Err(e)),
};
Some(
PhyloTree::from_newick(&bytes)
.map_err(|e| Error::new(ErrorKind::InvalidData, e.to_string())),
)
}
}

#[cfg(test)]
mod tests {
use std::{fs::File, io::BufReader};

use super::*;

fn get_scanner(file_name: &str) -> Scanner<BufReader<File>> {
let path = format!("{}/tests/data/{}", env!("CARGO_MANIFEST_DIR"), file_name);
let file_handle = File::open(path).unwrap();
Scanner::new(BufReader::new(file_handle))
}

#[test]
fn test_scanner_newick_multitree_file() {
let mut scanner = get_scanner("basic_trees.nw");
let first_tree = scanner.next().unwrap().unwrap();
assert_eq!(String::from_utf8(first_tree).unwrap(), "(,,(,));")
}

#[test]
fn test_basic_parsing() {
let scanner = get_scanner("basic_trees.nw");
let mut parser = PhyloParser::new(scanner);
let first_tree = parser.next().unwrap().unwrap();
assert_eq!(first_tree.to_newick().to_string(), "(,,(,));");
}
}
8 changes: 8 additions & 0 deletions phylo/tests/data/basic_trees.nw
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
(,,(,));
(A,B,(C,D));
(A,B,(C,D)E)F;
(:0.1,:0.2,(:0.3,:0.4):0.5);
(:0.1,:0.2,(:0.3,:0.4):0.5):0.0;
(A:0.1,B:0.2,(C:0.3,D:0.4):0.5);
(A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F;
((B:0.2,(C:0.3,D:0.4)E:0.5)F:0.1)A;
Loading