use super::*;
#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub enum ProteinFilter {
SpectralCounts(u16),
SequenceCounts(u16),
ExcludeReverse,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum PeptideFilter<'a> {
SequenceMatch(&'a str),
SequenceExclude(&'a str),
TotalIntensity(u32),
TotalIntensityChannels(Vec<usize>, u32),
ChannelCV(Vec<usize>, f64),
ChannelIntensity(usize, u32),
Purity(f32),
Tryptic,
Unique,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Filter<'a> {
#[cfg_attr(feature = "serde", serde(borrow))]
peptide_filters: Vec<PeptideFilter<'a>>,
protein_filters: Vec<ProteinFilter>,
}
impl<'a> Default for Filter<'a> {
fn default() -> Self {
Filter {
peptide_filters: Vec::new(),
protein_filters: Vec::new(),
}
}
}
impl<'a> Filter<'a> {
pub fn add_protein_filter(mut self, filter: ProteinFilter) -> Self {
self.protein_filters.push(filter);
self
}
pub fn add_peptide_filter(mut self, filter: PeptideFilter<'a>) -> Self {
self.peptide_filters.push(filter);
self
}
pub fn tryptic_regex() -> regex::Regex {
regex::RegexBuilder::new(r#"(R|K|-)\..*((R|K)\..|.-)"#)
.build()
.unwrap()
}
pub fn filter_dataset(&self, dataset: Dataset) -> Dataset {
let reg = Self::tryptic_regex();
Dataset {
channels: dataset.channels,
proteins: dataset
.proteins
.into_iter()
.filter_map(|prot| self.filter_protein(prot, ®))
.collect(),
}
}
pub fn filter_protein(
&self,
mut protein: Protein,
tryptic_regex: ®ex::Regex,
) -> Option<Protein> {
for filter in &self.protein_filters {
match filter {
ProteinFilter::SequenceCounts(n) => {
if protein.sequence_count < *n {
return None;
}
}
ProteinFilter::SpectralCounts(n) => {
if protein.spectral_count < *n {
return None;
}
}
ProteinFilter::ExcludeReverse => {
if protein.accession.contains("Reverse") {
return None;
}
}
}
}
let mut filtered = Vec::new();
for peptide in protein.peptides {
let mut pass = true;
for filter in &self.peptide_filters {
match filter {
PeptideFilter::SequenceExclude(pat) => {
if peptide.sequence.contains(pat) {
pass = false;
break;
}
}
PeptideFilter::SequenceMatch(pat) => {
if !peptide.sequence.contains(pat) {
pass = false;
break;
}
}
PeptideFilter::TotalIntensity(n) => {
if peptide.values.iter().sum::<u32>() < *n {
pass = false;
break;
}
}
PeptideFilter::Tryptic => {
if !tryptic_regex.is_match(&peptide.sequence) {
pass = false;
break;
}
}
PeptideFilter::Unique => {
if !peptide.unique {
pass = false;
break;
}
}
PeptideFilter::Purity(cutoff) => {
if peptide.purity < *cutoff {
pass = false;
break;
}
}
PeptideFilter::ChannelCV(channels, cutoff) => {
let mut v = Vec::new();
for chan in channels.iter() {
if chan - 1 < peptide.values.len() {
v.push(peptide.values[chan - 1]);
}
}
if util::cv(&v) >= *cutoff {
pass = false;
break;
}
}
PeptideFilter::ChannelIntensity(channel, cutoff) => {
if channel - 1 < peptide.values.len()
&& peptide.values[channel - 1] < *cutoff
{
pass = false;
break;
}
}
PeptideFilter::TotalIntensityChannels(chan, cutoff) => {
let mut sum = 0;
for c in chan {
if c - 1 < peptide.values.len() {
sum += peptide.values[*c - 1];
}
}
if sum < *cutoff {
pass = false;
break;
}
}
}
}
if pass {
filtered.push(peptide)
}
}
if filtered.len() == 0 {
return None;
}
protein.peptides = filtered;
let spec = protein.peptides.len() as u16;
let seq = protein
.peptides
.iter()
.map(|pep| &pep.sequence)
.collect::<HashSet<_>>()
.len() as u16;
protein.spectral_count = spec;
protein.sequence_count = seq;
for filter in &self.protein_filters {
match filter {
ProteinFilter::SequenceCounts(n) => {
if seq < *n {
return None;
}
}
ProteinFilter::SpectralCounts(n) => {
if spec < *n {
return None;
}
}
_ => {}
}
}
Some(protein)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn total_intensity_channels() {
let p1 = Peptide {
sequence: "aa".into(),
values: vec![1, 2998, 5000, 84, 4738, 9384],
unique: true,
scan: 0,
purity: 1.0,
};
let p2 = Peptide {
sequence: "aaa".into(),
values: vec![10000, 0, 433, 61346, 41, 5555],
unique: true,
scan: 0,
purity: 1.0,
};
let p3 = Peptide {
sequence: "aaaa".into(),
values: vec![1, 2999, 0, 0, 0, 0],
unique: true,
scan: 0,
purity: 1.0,
};
let prot = Protein {
accession: "".into(),
description: "".into(),
spectral_count: 10,
sequence_count: 3,
sequence_coverage: 0.3,
molecular_weight: 10,
peptides: vec![p1.clone(), p2.clone(), p3.clone()],
channels: 6,
};
let mut fil = Filter {
peptide_filters: Vec::new(),
protein_filters: Vec::new(),
};
fil = fil.add_peptide_filter(PeptideFilter::TotalIntensityChannels(vec![1, 2], 3000));
let p = fil.filter_protein(prot, &Filter::tryptic_regex()).unwrap();
assert_eq!(p.peptides.len(), 2);
assert_eq!(p.sequence_count, 2);
assert_eq!(p.peptides, vec![p2.clone(), p3.clone()]);
}
}