///|
/// QFeatures module demo - quantitative proteomics data management.
///
/// Run: moon run examples/qfeatures_demo
fn main {
println("=== QFeatures Module Demo ===")
println("Quantitative proteomics: PSM -> peptide -> protein aggregation")
println(
"Reference: Gatto L et al. (2020) QFeatures, bioRxiv 2020.10.27.358273",
)
println("")
// ------------------------------------------------------------------
// 1. Load sample QFeatures data
// ------------------------------------------------------------------
println("=== 1. Load sample QFeatures data ===")
let qf = @bio.qf_sample_data()
println(@bio.qf_summary(qf))
println("")
// ------------------------------------------------------------------
// 2. Print summary (n_assays, assay_names, dimensions)
// ------------------------------------------------------------------
println("=== 2. Assay overview ===")
println("n_assays: \{qf.n_assays()}")
let names = qf.assay_names()
let mut i = 0
while i < names.length() {
match qf.get_assay(names[i]) {
Some(a) =>
println(" \{names[i]}: \{a.n_rows()} features x \{a.n_cols()} samples")
None => println(" \{names[i]}: not found")
}
i = i + 1
}
println("Total links: \{qf.links().n_links()}")
println("")
// ------------------------------------------------------------------
// 3. Show PSM assay details (first few rows)
// ------------------------------------------------------------------
println("=== 3. PSM assay details ===")
let psm = qf.get_assay("psm").unwrap()
println(@bio.qf_assay_summary(psm))
let col_names = psm.col_names()
let header = " feature\t" + col_names.join("\t")
println(header)
let n_show = if psm.n_rows() < 4 { psm.n_rows() } else { 4 }
let mut r = 0
while r < n_show {
let mut line = " " + psm.row_names()[r]
let mut c = 0
while c < psm.n_cols() {
line = line + "\t" + psm.get(r, c).to_string()
c = c + 1
}
println(line)
r = r + 1
}
println("")
// ------------------------------------------------------------------
// 4. Show links between PSM and peptide levels
// ------------------------------------------------------------------
println("=== 4. Links between PSM and peptide levels ===")
let mut p = 0
while p < psm.n_rows() {
let links = qf.links().get_links_from("psm", p)
let mut l = 0
while l < links.length() {
let link = links[l]
let peptide = qf.get_assay("peptide").unwrap()
let pep_name = peptide.row_names()[link.to_row()]
println(
" PSM \{psm.row_names()[p]} (row \{p}) -> \{link.to_assay()} row \{link.to_row()} (\{pep_name})",
)
l = l + 1
}
p = p + 1
}
println("")
// ------------------------------------------------------------------
// 5. Apply log2 transform to PSM assay, show transformed values
// ------------------------------------------------------------------
println("=== 5. log2 transform of PSM assay ===")
let psm_log = @bio.qf_log_transform(psm, 2.0, 1.0)
println("Before (row 0): " + row_to_string(psm, 0))
println("After (row 0): " + row_to_string(psm_log, 0))
println("")
// ------------------------------------------------------------------
// 6. Filter low abundance features
// ------------------------------------------------------------------
println("=== 6. Filter low abundance PSM features ===")
let qf_filtered = @bio.qf_filter_low_abundance(qf, "psm", 15.0)
let psm_filtered = qf_filtered.get_assay("psm").unwrap()
println(
"PSM features: \{psm.n_rows()} -> \{psm_filtered.n_rows()} (threshold=15.0)",
)
println("Remaining PSM rows:")
let mut f = 0
while f < psm_filtered.n_rows() {
println(" \{psm_filtered.row_names()[f]}")
f = f + 1
}
println("")
// ------------------------------------------------------------------
// 7. Normalize using center/scale
// ------------------------------------------------------------------
println("=== 7. Center/scale normalization (peptide assay) ===")
let peptide = qf.get_assay("peptide").unwrap()
let peptide_norm = @bio.qf_normalize_center_scale(peptide, true, true)
println("Peptide before normalization (row 0): " + row_to_string(peptide, 0))
println(
"Peptide after normalization (row 0): " + row_to_string(peptide_norm, 0),
)
println("")
// ------------------------------------------------------------------
// 8. Show final protein-level assay values
// ------------------------------------------------------------------
println("=== 8. Protein-level assay ===")
let protein = qf.get_assay("protein").unwrap()
println(@bio.qf_assay_summary(protein))
let header2 = " protein\t" + protein.col_names().join("\t")
println(header2)
let mut pr = 0
while pr < protein.n_rows() {
let mut line = " " + protein.row_names()[pr]
let mut pc = 0
while pc < protein.n_cols() {
line = line + "\t" + protein.get(pr, pc).to_string()
pc = pc + 1
}
println(line)
pr = pr + 1
}
println("")
// ------------------------------------------------------------------
// 9. Convert protein assay to long format and show first few entries
// ------------------------------------------------------------------
println("=== 9. Protein assay in long format ===")
let long = @bio.qf_to_long_format(qf, "protein")
println("Total long-format entries: \{long.length()}")
let n_long = if long.length() < 6 { long.length() } else { 6 }
println(" protein\tsample\tvalue")
let mut g = 0
while g < n_long {
let (feat, sample, value) = long[g]
println(" \{feat}\t\{sample}\t\{value}")
g = g + 1
}
println("=== Demo complete ===")
}
///|
/// Format a single assay row as a tab-separated string of values.
fn row_to_string(assay : @bio.QfAssay, row : Int32) -> String {
let mut s = ""
let mut c = 0
while c < assay.n_cols() {
s = s + assay.get(row, c).to_string()
if c < assay.n_cols() - 1 {
s = s + ", "
}
c = c + 1
}
s
}