Skip to content

Commit

Permalink
Update for main branch of rustyms (immonium ions)
Browse files Browse the repository at this point in the history
Signed-off-by: Douwe Schulte <[email protected]>
  • Loading branch information
douweschulte committed Mar 28, 2024
1 parent 2fd957a commit a97e8d7
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 106 deletions.
2 changes: 0 additions & 2 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ rustyms = { version = "0.8.3", default-features = false, features = [
"align",
] }

[patch.crates-io]
rustyms = { path = "../../rustyms/rustyms" }

[features]
# by default Tauri runs in production mode
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
Expand Down
2 changes: 2 additions & 0 deletions src-tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ fn main() {
<div class="empty"></div>
{}
<input type="text" id="model-precursor-loss" value="" title="Supply all losses as +/- followed by the chemical formula, supply multiple by separating them by commas. Example: '+H2O,-H2O'."/>
<label>immonium</label>
<label><input id='model-immonium-enabled' type='checkbox' switch/>Enable</label>
<label>glycan</label>
<label><input id='model-glycan-enabled' type='checkbox' switch/>Enable</label>
{}
Expand Down
50 changes: 27 additions & 23 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use render::display_mass;
use rustyms::{
align::{align, matrix::BLOSUM62, Alignment},
error::*,
fragment::FragmentType,
identification::*,
model::*,
modification::{GnoComposition, ModificationSearchResult, Ontology, ReturnModification},
Expand Down Expand Up @@ -201,26 +202,29 @@ async fn search_modification(text: &str, tolerance: f64) -> Result<String, Strin
let mut ul = HtmlElement::new(HtmlTag::ul);

for rule in rules {
match rule {
PlacementRule::AminoAcid(aa, pos) => {
ul = ul.content(HtmlElement::new(HtmlTag::li).content(format!(
"{}@{}",
aa.iter().map(|a| a.char()).collect::<String>(),
pos
)));
}
PlacementRule::PsiModification(index, pos) => {
ul = ul.content(HtmlElement::new(HtmlTag::li).content(format!(
"{}@{}",
Ontology::Psimod.find_id(*index).unwrap(),
pos
)));
}
PlacementRule::Terminal(pos) => {
ul = ul
.content(HtmlElement::new(HtmlTag::li).content(format!("{}", pos)));
}
}
ul = ul.content(HtmlElement::new(HtmlTag::li).content(
format!("Positions: {}, Neutral losses: {}, Diagnostic ions: {}",&rule.0.iter().map(|rule| match rule {
PlacementRule::AminoAcid(aa, pos) => {
format!(
"{}@{}",
aa.iter().map(|a| a.char()).collect::<String>(),
pos
)
}
PlacementRule::PsiModification(index, pos) => {
format!(
"{}@{}",
Ontology::Psimod.find_id(*index).unwrap(),
pos
)
}
PlacementRule::Terminal(pos) => {
format!("{}", pos)
}
}).join(",") ,
rule.1.iter().join(","),
rule.2.iter().map(|ion| ion.0.to_string()).join(","))
));
}
output = output.content(ul);
} else if let Modification::Gno(composition, name) = &modification {
Expand Down Expand Up @@ -528,6 +532,7 @@ pub struct ModelParameters {
pub y: (Location, String),
pub z: (Location, String),
pub precursor: String,
pub immonium: bool,
pub glycan: (bool, String),
}

Expand Down Expand Up @@ -587,26 +592,25 @@ async fn annotate_spectrum<'a>(
get_model_param(&cmodel.z)?,
cmodel
.precursor
.to_owned()
.split(',')
.filter(|n| !n.is_empty())
.map(|n| n.parse::<NeutralLoss>())
.collect::<Result<Vec<NeutralLoss>, _>>()?,
MassOverCharge::new::<mz>(ppm),
cmodel.immonium,
cmodel
.glycan
.0
.then(|| {
cmodel
.glycan
.1
.to_owned()
.split(',')
.filter(|n| !n.is_empty())
.map(|n| n.parse::<NeutralLoss>())
.collect::<Result<Vec<NeutralLoss>, _>>()
})
.invert()?,
MassOverCharge::new::<mz>(ppm),
),
_ => Model::all(),
};
Expand Down
143 changes: 64 additions & 79 deletions src-tauri/src/render.rs
Original file line number Diff line number Diff line change
@@ -1,70 +1,13 @@
use std::{cmp::Ordering, collections::HashSet, fmt::Write};

use itertools::{all, Itertools};
use itertools::Itertools;
use rustyms::{
fragment::*,
model::Location,
spectrum::{AnnotatedPeak, PeakSpectrum},
system::*,
AnnotatedSpectrum, ComplexPeptide, Element, LinearPeptide, MassMode, Model, Modification,
MolecularFormula, MultiChemical,
fragment::*, model::Location, spectrum::PeakSpectrum, system::*, AnnotatedSpectrum,
ComplexPeptide, LinearPeptide, MassMode, Model, Modification, MolecularFormula, MultiChemical,
};

use crate::html_builder::{HtmlElement, HtmlTag};

pub fn fragment_table(fragments: &[Fragment], multiple_peptides: bool) -> String {
let mut output = format!("<table><thead><tr><th>Sequence Index</th><th>Series Number</th><th>Ion</th><th>mz</th><th>Charge</th><th>Neutral loss</th>{}</tr></thead><tbody>", if multiple_peptides {
"<td>Peptide</td>"
} else {
""
});
for fragment in fragments {
let (sequence_index, series_number) = if let Some(pos) = fragment.ion.position() {
(
pos.sequence_index.to_string(),
pos.series_number.to_string(),
)
} else if let Some(pos) = fragment.ion.glycan_position() {
(pos.attachment(), pos.series_number.to_string())
} else if let FragmentType::InternalGlycan(breakages) = &fragment.ion {
(
breakages
.get(0)
.map(|b| b.position().attachment())
.unwrap_or("-".to_string()),
breakages
.iter()
.map(std::string::ToString::to_string)
.join(""),
)
} else {
// precursor
("-".to_string(), "-".to_string())
};
write!(
&mut output,
"<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td>{}</tr>",
sequence_index,
series_number,
fragment.ion.label(),
fragment.mz(MassMode::Monoisotopic).value,
fragment.charge.value,
fragment
.neutral_loss
.as_ref()
.map_or("-".to_string(), |n| n.to_string()),
if multiple_peptides {
format!("<td>{}</td>", fragment.peptide_index + 1)
} else {
String::new()
}
)
.unwrap();
}
write!(&mut output, "</tbody></table>").unwrap();
output
}

pub fn annotated_spectrum(
spectrum: &AnnotatedSpectrum,
id: &str,
Expand Down Expand Up @@ -330,7 +273,7 @@ fn spectrum_graph(
/// * The position(s) (eg 'p0-2', 'p2-123')
fn get_classes(annotations: &[Fragment]) -> String {
let mut output = Vec::new();
let mut shared_ion = annotations.get(0).map(|a| a.ion.to_string());
let mut shared_ion = annotations.first().map(|a| a.ion.to_string());
let mut first_peptide_index = None;
for annotation in annotations {
output.push(annotation.ion.label().to_string());
Expand All @@ -351,7 +294,7 @@ fn get_classes(annotations: &[Fragment]) -> String {
if annotation.ion.glycan_position().is_some() {
output.push("glycan".to_string());
}
if matches!(annotation.ion, FragmentType::InternalGlycan(_)) {
if matches!(annotation.ion, FragmentType::Oxonium(_)) {
output.push("glycan".to_string());
output.push("internal_glycan".to_string());
}
Expand Down Expand Up @@ -388,8 +331,8 @@ fn get_label(annotations: &[Fragment], multiple_peptides: bool, multiple_glycans
shared_charge = None;
}
}
if let Some(ion) = shared_ion {
if ion != a.ion.label() {
if let Some(ion) = &shared_ion {
if *ion != a.ion.label() {
shared_ion = None;
}
}
Expand Down Expand Up @@ -427,7 +370,9 @@ fn get_label(annotations: &[Fragment], multiple_peptides: bool, multiple_glycans
let charge_str = shared_charge
.map(|charge| format!("{:+}", charge.value))
.unwrap_or("*".to_string());
let ion_str = shared_ion.unwrap_or("*");
let ion_str = shared_ion
.map(|c| c.into_owned())
.unwrap_or("*".to_string());
let pos_str = shared_pos
.map(|pos| pos.unwrap_or_default())
.unwrap_or("*".to_string());
Expand All @@ -445,7 +390,7 @@ fn get_label(annotations: &[Fragment], multiple_peptides: bool, multiple_glycans
let multi = if annotations.len() > 1 {
let mut multi = String::new();
for annotation in annotations {
if let FragmentType::InternalGlycan(breakages) = &annotation.ion {
if let FragmentType::Oxonium(breakages) = &annotation.ion {
let ch = format!("{:+}", annotation.charge.value);
write!(
multi,
Expand Down Expand Up @@ -503,11 +448,10 @@ fn get_label(annotations: &[Fragment], multiple_peptides: bool, multiple_glycans
String::new()
};
let single_internal_glycan =
matches!(annotations[0].ion, FragmentType::InternalGlycan(_))
&& annotations.len() == 1;
matches!(annotations[0].ion, FragmentType::Oxonium(_)) && annotations.len() == 1;

if single_internal_glycan {
if let FragmentType::InternalGlycan(breakages) = &annotations[0].ion {
if let FragmentType::Oxonium(breakages) = &annotations[0].ion {
format!(
"<span>{}<sup>{}</sup><sub style='margin-left:-{}ch;min-width:{2}ch;display:inline-block;'>{}{}</sub>{}</span>",
breakages
Expand Down Expand Up @@ -611,7 +555,7 @@ fn render_peptide(
ComplexPeptide::Singular(peptide) => {
render_linear_peptide(output, peptide, &overview[0], 0, multiple_peptides)
}
ComplexPeptide::Multimeric(peptides) => {
ComplexPeptide::Chimeric(peptides) => {
for (index, peptide) in peptides.iter().enumerate() {
render_linear_peptide(output, peptide, &overview[index], index, multiple_peptides);
}
Expand Down Expand Up @@ -657,12 +601,14 @@ fn render_linear_peptide(
)
.unwrap();
for ion in ions {
write!(
output,
"<span class='corner {}'></span>",
ion.label().trim_end_matches('·')
)
.unwrap();
if !matches!(ion, FragmentType::immonium(_, _)) {
write!(
output,
"<span class='corner {}'></span>",
ion.label().trim_end_matches('·')
)
.unwrap();
}
}
write!(output, "</span>").unwrap();
}
Expand Down Expand Up @@ -811,18 +757,33 @@ pub fn spectrum_table(
format!("{}{}", pos.series_number, pos.branch_names()),
annotation.ion.label().to_string(),
)
} else if let FragmentType::InternalGlycan(breakages) = &annotation.ion {
} else if let FragmentType::Oxonium(breakages) = &annotation.ion {
(
breakages
.first()
.map(|b| b.position().attachment())
.unwrap_or("-".to_string()),
"-".to_string(),
breakages
.iter()
.filter(|b| !matches!(b, GlycanBreakPos::End(_)))
.map(|b| format!("{}<sub>{}</sub>", b.label(), b.position().label()))
.join(""),
"oxonium".to_string(),
)
} else if let FragmentType::Y(bonds) = &annotation.ion {
(
bonds
.first()
.map(|b| b.attachment())
.unwrap_or("-".to_string()),
bonds.iter().map(|b| b.label()).join(""),
"Y".to_string(),
)
} else if let FragmentType::immonium(aa, pos) = &annotation.ion {
(
(pos.sequence_index + 1).to_string(),
pos.series_number.to_string(),
format!("immonium {}", aa.char()),
)
} else {
// precursor
Expand Down Expand Up @@ -978,6 +939,8 @@ struct IonStats<T> {
x: T,
y: T,
z: T,
immonium: T,
m: T,
precursor: T,
oxonium: T,
Y: T,
Expand All @@ -1004,6 +967,8 @@ where
let mut seen_x = false;
let mut seen_y = false;
let mut seen_z = false;
let mut seen_immonium = false;
let mut seen_m = false;
let mut seen_precursor = false;
let mut seen_oxonium = false;
#[allow(non_snake_case)]
Expand Down Expand Up @@ -1049,7 +1014,15 @@ where
self.z += value;
seen_z = true;
}
FragmentType::B(..) | FragmentType::InternalGlycan(..)
FragmentType::immonium(..) if !seen_immonium || allow_double_counting => {
self.immonium += value;
seen_immonium = true;
}
FragmentType::m(..) if !seen_m || allow_double_counting => {
self.m += value;
seen_m = true;
}
FragmentType::B(..) | FragmentType::Oxonium(..)
if !seen_oxonium || allow_double_counting =>
{
self.oxonium += value;
Expand Down Expand Up @@ -1101,6 +1074,12 @@ where
if self.z > T::default() {
result.push(callback("z", self.z, single));
}
if self.immonium > T::default() {
result.push(callback("immonium", self.z, single));
}
if self.m > T::default() {
result.push(callback("m", self.z, single));
}
if self.precursor > T::default() {
result.push(callback("precursor", self.precursor, single));
}
Expand Down Expand Up @@ -1143,6 +1122,12 @@ where
if self.z > T::default() {
result.push(callback("z", self.z, other.z));
}
if self.immonium > T::default() {
result.push(callback("immonium", self.immonium, other.immonium));
}
if self.m > T::default() {
result.push(callback("m", self.m, other.m));
}
if self.precursor > T::default() {
result.push(callback("precursor", self.precursor, other.precursor));
}
Expand Down
4 changes: 3 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,10 @@ async function annotate_spectrum() {
y: [get_location("#model-y-location"), get_losses("y")],
z: [get_location("#model-z-location"), get_losses("z")],
precursor: get_losses("precursor"),
glycan: [document.querySelector("#model-glycan-enabled").value == "on", get_losses("glycan")],
immonium: document.querySelector("#model-immonium-enabled").checked,
glycan: [document.querySelector("#model-glycan-enabled").checked, get_losses("glycan")],
};
console.log(model);
invoke("annotate_spectrum", { index: Number(document.querySelector("#details-spectrum-index").value), ppm: Number(document.querySelector("#spectrum-ppm").value), charge: charge, filter: noise_threshold, model: document.querySelector("#spectrum-model").value, peptide: document.querySelector("#peptide").innerText, cmodel: model }).then((result) => {
document.querySelector("#spectrum-results-wrapper").innerHTML = result.spectrum;
document.querySelector("#spectrum-fragment-table").innerHTML = result.fragment_table;
Expand Down
Loading

0 comments on commit a97e8d7

Please sign in to comment.