NEWS.md
estimate.power function to compute sample size and power estimationheatmap.counts.anno(): the heatmap of heatmap.counts(), with the same data selection (which.data, contrast, top.n, sample.subset, protein.subset, group.by.metadata.column, scale), drawn with ComplexHeatmap instead of ggplot2. It returns the usual DEprot.counts.heatmap object, whose heatmap slot contains a Heatmap object, hence it can be customized, drawn and concatenated with the standard ComplexHeatmap syntaxComplexHeatmap and circlize added to the dependenciesgenerate.mm to generate materials and methods paragraphDEprot.analyses is now defined as an extension of the DEprot class (contains = "DEprot") instead of repeating its slot list: the two classes cannot drift apart anymoreanalyses.result.list, contrasts and differential.analyses.params are no longer slots of DEprot, where they were declared but never filledmethods::is(x, "DEprot"), which is satisfied by DEprot.analyses objects as wellupdateObject() method for DEprot: it removes the three unused slots from the objects restored from a .rds file written with a previous versionperform.sPLSDA(): sparse Partial Least Squares Discriminant Analysis (sPLS-DA) on a DEprot object. Differently from the PCA and the PCoA, which show the largest source of variability whatever its origin, it looks for the directions separating a set of classes given by the user and selects the proteins responsible for that separationkeepX and the estimation of the classification performances happen inside perform.sPLSDA(): neither of them changes as long as the model does not change. The tuning runs when keepX = NULL, the validation when validate = TRUE
ncomp is raised to 3 when a lower value is requested, and the number of folds is capped to the size of the smallest class (leave-one-out below 3 samples per class)reference.group always sits on the positive side: the orientation returned by mixOmics is arbitrary and would change from one run to the next. The object stored in the splsda slot keeps the original mixOmics orientationDEprot.sPLSDA class, with its show, summary and plot methodsget.sPLSDA.results(), get.sPLSDA.proteins() and get.sPLSDA.ranking()
sPLSDA.enrichment(): GSEA on the complete ranking, over-representation on the selected proteins, using as background the proteins that entered the model. It returns the usual DEprot.enrichResult object, hence NES.plot(), plot.GSEA(), simplify.enrichment(), combine.enrichments() and divergent.enrichment() work on it unchangedplot.sPLSDA.scatter(), plot.sPLSDA.scatter.123(), plot.sPLSDA.cumulative(), plot.sPLSDA.biplot(), plot.sPLSDA.loadings(), plot.sPLSDA.tuning(), plot.sPLSDA.performance(), plot.sPLSDA.stability() and plot.sPLSDA.auroc()
.ordination.slots() accepts DEprot.sPLSDA objects.append.protein.info(), used by get.sPLSDA.results() to append the protein.info annotationmixOmics added to the dependenciescompare.imp.methods() gains masking, which defines how the values of the test dataset are hidden. With "MCAR" (default, previous behaviour) every measured value has the same probability of being masked; with "intensity" the probability follows a logistic dropout curve estimated on the data, so that the masked values come from the low-intensity range at the rate at which the values are really lostdropout.by = "group") or for each sample (dropout.by = "sample"): an IgG control and an IP do not have the same detection depth and cannot be masked with the same curve. The curves are fitted on the complete table, since the proteins absent from an entire group carry the information about the detection limit and cannot belong to the test datasetmax.NA.per.row defines how many missing values a protein can already have to be usable in the test dataset. The error is computed only on the masked cells, hence a protein does not need to be complete: keeping only the complete ones restricted the comparison to the abundant proteins, which hold less than a fifth of the values of the bottom 3% of the distribution. max.NA.fraction caps the missingness reached after the masking, so that the table stays usable by missForest and by the other methods needing a minimum number of values per proteinmasking slot of the DEprot.RMSE objectsseed
load.counts* the columns of the counts are now reordered to match the same order fo the metadata tableimpute.counts the missForest mode was not using the seed provided by the user, now fixeddiff.analyses.prolfqua: the counts are handed to prolfqua directly in log2 scale and flagged as already transformed. They were converted back to the linear scale (2^x - 1) before the fit and log2-transformed again by prolfqua: the round trip does not return the starting values, the distortion grows towards the bottom of the distribution and does not cancel out in the contrast, and a value at or below 1 fell on 0 or on a negative intensity, switching the conversion of the whole contrast. The "logistf" strategy has been removed: Firth’s regression models the detection of a protein through a binary response and cannot return a fold change, while it was receiving the log2 abundances as response and its coefficients were reported as log2(FoldChange)heatmap.counts keeps the order of samples/proteins provided for a subset (if no cluster is involved)geneset.enrichment() now applies pvalueCutoff and qvalueCutoff to the GSEA results as well: clusterProfiler::GSEA() does not provide a q-value threshold and, depending on the version installed, does not always filter on the adjusted p-values, hence genesets with an adjusted p-value and a q-value far above the thresholds requested were reported as significant. The three conditions (uncorrected p-value, adjusted p-value and q-value) are verified by DEprot itself on both ORA and GSEA results, and the genesets whose q-value could not be estimated (NA) are keptNES.plot(), and in the NES plot returned by geneset.enrichment(), the transparency of the bars stays mapped on the -log10 of the adjusted p-value, but the legend is now labelled with the p-values themselves: the breaks are spaced logarithmically and picked among round values (0.05, 0.01, 0.001, …), so that the most opaque bars remain the most significant while the numbers displayed can be read directly. An adjusted p-value of 0 no longer results in an infinite transparencyNULL instead of interrupting the analyses, and NES.plot() stops with an explicit messageload.counts2() (and load.counts()) accept a protein.info table at loading; the IDs can be given as row names, in a prot.id column or in any column indicated by protein.info.id.column. The table is re-ordered on the counts: unannotated proteins are filled with NA and annotations of proteins absent from the counts are discardedadd.protein.info() to attach, replace or remove the annotation of an object built previouslyget.protein.info() to extract the annotation table from an object, in the same fashion as get.metadata()filter.proteins(), remove.undetected.proteins(), harmonize.batches(), filter.samples() and by all the diff.analyses*() functionsget.results() gains protein.info.columns and protein.info.prefix: the annotation is appended only on request, using the keywords “none” (default) and “all” or a vector of column names. The columns are bound to the results by protein ID (not by position) and colliding names are made uniqueexport.analyses() writes the annotated results tablesmissingness.diagnostic(): classifies the missing values as MNAR-like or MCAR-like following the same rule of the double-imputation strategy, estimates the limit of detection by a logistic dropout model (LOD50), and returns the diagnostic plots (detection vs abundance densities, dropout curve, imputation map, Jaccard similarity of the detection patterns with dendrogram, per-sample and per-class summaries, UpSet of the MNAR-like patterns)randomize.missing.values (group.column, percentage.missing, tail.percentage) are retrieved automatically when the randomization has already been run; the counts are selected at the lowest level available (raw > normalized > randomized > imputed)DEprot.analyses object is provided, including the directional MNAR classification and the testable flag for the proteins missing in both groupsDEprot.missingness with show, summary and plot methodsComplexUpset themes in plot.upset(), which were not valid anymore since ggplot2 v4.0.0analyze.timecourse() returns an object of the new class DEprot.timecourse (with show, summary and plot methods). Time is handled as a numeric covariate: a natural-spline basis is fitted by limma and all the time coefficients are tested jointly by a moderated F-test, resulting in a single test per protein and therefore in no contrast to defineanalyze.timecourse(): the spline degrees of freedom are capped automatically at n.timepoints - 2 (a saturated spline being equivalent to treating the time as a factor), and a linear trend is fitted below 4 timepoints; the time.transform option (log2, log10, log1p, sqrt) re-spaces log-spaced designs so that the last timepoint does not dominate the fitanalyze.timecourse(): the results table reports the kinetic descriptors of each fitted trajectory (amplitude, initial.slope, peak.time, trend.shape: monotone/transient/complex) together with the cluster assignment, the membership and the ranking scoreanalyze.timecourse(): the trending proteins are soft-clustered (c-means, or PAM) on the Z-scored fitted curves rather than on the raw timepoint means, which makes the clustering robust to unequal time spacing and to missing values; the fuzzifier and the number of clusters are estimated from the data when not providedrank.timecourse() to re-rank the proteins, globally and within each cluster, without refitting the model, and get.timecourse.results() to retrieve the results with cluster/top-N subsettingplot.timecourse.protein() (measured points, mean ± SEM and fitted trajectory of individual proteins) and plot.timecourse.profiles() (one panel per cluster, lines colored by membership). Both accept values = "counts", "log2FC" (relative to reference.time) or "zscore"
heatmap.timecourse(): heatmap of the trending proteins with the rows split by cluster, sortable by rank, membership, peak.time, amplitude or hclust, and displaying either the measured means or the smooth fitted trajectoriestimecourse.enrichment(): over-representation analyses run independently on each cluster, using all the quantified proteins as universe, returning an object of the new class DEprot.timecourse.enrichment (with show and plot methods). The dotplot shows the enrichment as dot size, the significance as color, and the number of proteins of the geneset written inside each dotsplines, e1071 and cluster added to the dependenciescombine.enrichments(): merges a named list of enrichments in a single dotplot, with the discoveries on the x-axis and the genesets on the y-axis; the dots are sized by fold enrichment or gene ratio, colored by significance, and carry the protein count insidedivergent.enrichment(): plots two enrichments back-to-back, the second one with the sign inverted, to show together the two sides of the same contrast (e.g. ORA of the up- and down-regulated proteins); bar length can be FoldEnrichment, GeneRatio, Count, NES or padj
DEprot.enrichResult, DEprot.timecourse.enrichment, enrichResult/gseaResult (clusterProfiler) objects and plain result tables; a DEprot.timecourse.enrichment is expanded into one discovery per cluster.parse.ratio(), .get.enrichment.table() and .collect.enrichments(), which harmonize the columns of GSEA and ORA results (for a GSEA the leading edge is used as equivalent of the ORA Count); timecourse.enrichment() now uses the exported .parse.ratio() instead of its local copyexport.external(): converts a DEprot/DEprot.analyses object into a SummarizedExperiment, QFeatures, MSnSet, limma::EList or a plain list of tables, with the shortcuts as.SummarizedExperiment(), as.QFeatures() and as.MSnSet()
protein.info together with the differential results become the row annotationkeep.object = TRUE allows a lossless round-tripSummarizedExperiment, QFeatures and MSnbase are optional dependencies: requested only when needed and never installed without confirmationdetect.outliers(): automatic per-sample QC flagging combining median inter-sample correlation, robust Mahalanobis distance in PC space and missing rate; returns a DEprot.outliers object (with show and plot methods) whose outliers slot can be passed directly to filter.samples()
diff.analyses.proDA(): differential analyses on left-censored data using proDA. The missing values are not replaced but modelled as observations below the detection limit, so that the uncertainty on the undetected values propagates into lfcSE instead of being compressed by the imputation. It requires counts that still contain the missing values (which.data = “normalized”) and it is the natural continuation of a strongly-MNAR verdict of missingness.diagnostic(), whose output can be passed directly through missingness.object the results table of diff.analyses.proDA() keeps the columns of the other differential functions and adds n.detected.filter.samples() recognizes the new engine and re-runs the contrasts with the stored parametersdiff.analyses.limma() now returns the lfdr column when padj.method = “fdrtool”, as already stated in the manual proDA added to the dependenciesimport.external(): builds a DEprot object directly from DIA-NN, Spectronaut, FragPipe, MaxQuant and Proteome Discoverer reports, with the shortcuts read.diann(), read.diann.matrix(), read.spectronaut(), read.fragpipe() and read.maxquant()
import.msstats() for the summarized objects of MSstats (label-free) and MSstatsTMT (isobaric); the metadata are reconstructed from the object annotation when not providediq (MaxLFQ summarization) and nanoparquet (DIA-NN .parquet reports) are optional dependencies: they are requested only when needed and never installed without confirmationplot.volcano and plot.MA can automatically plot the top N differential proteinsexport.report will plot the top.n proteins in the volcanoperform.PCoA() with plot.PCoA.scatter(), plot.PCoA.scatter.123(), plot.PCoA.cumulative() and plot.PCoA.biplot(), computed from a DEprot.correlation objectexpression.boxplot function can now show pair-wise comparisonsdiff.analyses.limma can use fdrtool to adjust the p-valuesplot method for objects of class DEprot, DEprot.analyses, DEprot.normality
filter.samples
export.report to export an HTML QC-reportcheck.pvalues when prolfqua tables are providedharmonize.batches(): added algorithm (ComBat/limma), ComBat.mode, and block; limma helps on sparse designs where ComBat hits a singular matrixharmonize.batches(): drop uncorrectable proteins with a warning, error on an empty result, and fix the algorithm/block defaultsload.counts2 automatically converts the counts into log2 transformed.diff.analyses, diff.analyses.limma and diff.analyses.prolfqua now return, for each group, the standard deviation (sd.<group>) and standard error of the mean (sem.<group>) of the log2 expression values, plus lfcSE, the standard error of the log2(FoldChange). The new columns are appended at the end of the results table. lfcSE is NA when stat.test = "wilcoxon"
NES.plot functionperform.PCA, diff.analyses*, plot.PC.buplot and the test.toolbox, as well as the vignette and manual.plot.PC.biplot.SAINTq and the rime.dpo and rime.saintq datasets.plot.PC.scatter to allow for the separate plotting of x and y zero-lines.randomize.missing.values is now included in a separate slot. Also the a new boxplot.random and randomization.method slots for the randomized scores have been added.imputation has been renamed into imputation.method. Many functions have been changed accordingly.compare.ranking function have been updated to compare all three methods.compare.imp.methods function and the new updates.randomize.missing.values function.check.normality function, which was inverting the evaluation of the AD’s test p-value.