NEWS.md
<QCThresholds> (and processing parameters via <Parameters>), overriding the hardcoded defaults in QC.R on a per-flag basis (issue #670). Flags absent from the XML fall back to their hardcoded defaults. New helper mergeQCCriteria() overlays XML thresholds onto the QC*Criteria() defaults (overriding only value-like fields; flag set, ordering, and thresholdNames stay code-defined). Supports per-matrix sample Detectability keys (Detectability_PLASMA → Detectability.plasma), appliesWhen="TAP" gating, and operator="none" informational-only rows (displayed, never flag). A new forceDefaultQC argument to loadNULISAseq() forces the hardcoded defaults and ignores the XML.AQ_NC_outlier_removal and AQ_IPC_outlier_removal (both default FALSE), plus AQ_IPC_outlier_threshold (default 3) and AQ_IPC_mad_floor (default 0.3). When enabled, a maximum of one NC and/or one IPC/CAL outlier is removed per-target during absolute quantification. Default behavior is unchanged. These options only take effect when AQ is computed via NULISAseqAQ::applyAQ; they are ignored in the XML-embedded fallback path.Target_Detectability) are now threshold=0 and operator="none": they display but never produce a pass/warning verdict. This is a permanent, non-overridable setting - mergeQCCriteria() explicitly excludes Detectability from panel-XML overrides, since many existing panel XML files carry a <QCThresholds> entry for it that mirrors the old hardcoded default and would otherwise silently re-enable flagging.NULL immediately when defaults is NULL (e.g. QCTargetCriteria(advancedQC=FALSE) on a plain RQ run), instead of proceeding to warn that every panel-XML <TargetQC> threshold key has “no matching computation.” Previously, any plain RQ run with panel-XML target thresholds warned on every QCFlagTarget() recompute (issue #702).NULISAseqAQ and XML-embedded fallback modes: the fallback path includes the blank_outlier_table and IPC_outlier_table elements (as NULL) that applyAQ() returns.NULISAseqAQ::applyAQ only when the installed version accepts them (filtered against formals()), preventing an “unused arguments” error and aborted AQ processing when an older NULISAseqAQ is installed.sig_targets list instead of grepl(target, ...) (which matched substrings like CCL1→CCL14 and regex metacharacters like LTA|LTB). Site B: per-plate pairwise fraction now matches plate names with a bounded pattern instead of grep(plate, ...) (which matched Plate_1→Plate_10), while still matching emmeans’ parenthesized factor levels.NULL) before calling emmeans::emmeans() (issue #655), which previously aborted the entire report with “Can’t handle an object of class NULL”.IC_normed$normData alongside Data/samples/SampleNames (issue #655), keeping columns aligned so the IC-normalized control CV% is computed on the correct wells.IPC/NC/SC/Bridge/Calibrator (issue #697). Previously, if the excluded well was itself an IPC/NC/SC/Bridge control (e.g. an IPC well with zero internal-control reads), its name lingered in those lists after its column was dropped from Data, causing interPlateNorm() to fail with “subscript out of bounds” and aborting QC report generation entirely.drop=FALSE, and the function now errors clearly (“No IPC wells remain…” / “No samples remain for intensity normalization…”) when a plate’s IPC list or resolved intensity-normalization sample set (which covers NC and Bridge-based normalization) is empty, rather than silently treating a missing control as “no normalization needed.” It also now validates that IPC well names/indices actually exist in the data, raising a specific “not found in the data” error instead of the generic “subscript out of bounds.” Previously, a plate left with exactly one control well after exclusion crashed with the opaque dim(X) must have a positive length, and a plate left with zero wells of a given type silently skipped that normalization step (e.g. IPC factors defaulted to 1) instead of failing - producing a report that looked normalized but wasn’t. This also closes the same hole for loadNULISAseq(excludeSamples=...), which routes through the same function. Also fixed IPC_method='mean', which previously errored on any input due to an argument passed positionally into the wrong parameter.drop=FALSE when subsetting them, instead of crashing with dim(X) must have a positive length when exactly one blank well remains after sample exclusion, or silently computing a meaningless single-sample LOD.grepl("", ...) matched every sample name and mislabeled all samples on that plate as “Bridge”. Also gave the sample-QC dotchart’s label index (inds) an explicit default so it can no longer be left undefined when neither the SC nor Bridge relabeling block runs for a plate.sanitize_names argument (default FALSE). When TRUE, covariate column names are passed through clean_covariate_names(case = "lower_camel") before being written as XML attributes, matching NAS’s covariate-upload sanitation so attribute names stay stable across NAS export → NULISAseqR import → NAS re-import (follow-up to Alamar-Biosciences/NULISA-Analysis-Software#3199). Default FALSE preserves the historical write-verbatim contract for direct callers. Errors with a clear message if sanitation would collide two original columns onto the same attribute name (e.g. sampleName + "Sample Name" both targeting sampleName)PlateID) by appending _covar suffix; emits a message when renaming occurs to inform users of the changedo.call(rbind) with dplyr::bind_rows() when aggregating samples across plates, fixing crashes when importing plates with different XML schemas (e.g. mismatched metadata columns)do.call(rbind) with dplyr::bind_rows() for RunSummary aggregation; drops NA-named slots from each plate’s RunSummary list to eliminate spurious NA. columns when plates have no balancers in the XMLis.na() instead of is.null() for XML attribute checks, fixing silent failures when attributes return NA rather than NULL
covariates$sampleName is plate-suffixed (e.g. LowQC_Plasma_begin_<plate>.xml), which previously produced NA for the injected covariate on every QC sample on re-import (issue Alamar-Biosciences/NULISA-Analysis-Software#3199). Match now anchors on either exact equality or the _<plate>.xml suffix used by NAS, avoiding both the prior silent-skip and the substring over-match it could regress into. Empty or whitespace-only barcode text is now skipped explicitlynoDetectability modifiernoDetectability modifier have individual detectability computed but are excluded from summary statistics (mean, sd, median, min, max, # detectable targets)exclude_targets parameter; consolidated and centralized detectability formatting logic to avoid duplication; “High Abundance” label now shown only for PLASMA/SERUM matrix types; detectability set to NA for non-plasma/serum sample types; returns numeric columns by default (format=FALSE) to preserve downstream computationinclude_IC_counts = TRUE
tolower) in quantifiability() and the QC report skeleton to ensure consistent ordering across platformsnoDetectability targets kept in batch effect assessment; guarded against edge caseslmNULISAseq.R); removed LazyData field; added withr to Suggestsapply() dimension drop in detectability output table; fixed rowSums NA handling and guarded against empty target sets in aggregationnoDetectability targets from detectability calculationsnoDetectability targets now correctly included in Failed_Targets for CV criterion onlynumericCovariates for list inputstibble:: prefix for column_to_rownames()
noDetectability target handlingxml_files parameter moved to first position for more intuitive usageoutput_filename (“NULISAseq_QC_Report.html”) and output_dir (current working directory)dataDir (current working directory)Rmd_input_file path construction using system.file()
data_matrix before blanks)targetNoOutlierDetection only includes targets present in data_matrix
intersect() to find common samples between Data_AQ_aM and SampleNames
LOD_pgmL (limit of detection in pg/mL units) from XML data for AQ assayslod() function call to use data_matrix= explicitlytest-importNULISAseq.R - Tests for importNULISAseq() function with and without NULISAseqAQ package, including fallback mode validation and AQ data consistency checkstest-reverse-curve.R - Tests for reverse curve target handling, including correlation validation, data transformation verification, and NPQ value consistency between loadNULISAseq() and importNULISAseq()
test-writeNULISAseq.R - Tests for Excel output generation with both RQ-only and AQ data, including validation of sheet structure, column names, and specific data valuesinst/rmarkdown/templates/nulisaseq/skeleton/ to tests/testthat/fixtures/ for better organization.gitignore file from skeleton template directoryAUTO_PLATE IDs with duplicate detection before processingexcludeSamples, excludeTargets, and control parameters (IC, IPC, SC, NC, Bridge, Calibrator) using prioritized keys (user-provided plate names, internal IDs, or fallback names)AUTO_PLATE ID from NULISAseq XML file headersVersion 1.4.0 represents a major expansion of the NULISAseqR package, introducing new analytical capabilities, enhanced visualization tools, and improved data processing functions.
loadNULISAseq() which accommodates absolute quantification (AQ) NULISAseq assay panelsFour new functions enable using single-target NPQ as a predictor in covariate-adjusted linear and logistic regression models:
withinDR matrix to AQ output for dynamic range filteringimportNULISAseq functionupper_log2FC_threshold and lower_log2FC_threshold parameters for labeling targets based on effect sizewriteNULISAseq (empty cells vs “NA” string)drop=FALSE)Full Changelog: https://github.com/Alamar-Biosciences/NULISAseqR/compare/main…1.4