Skip to content

Commit 688ff6d

Browse files
authored
feat(MSstats+): Add plot showing quality metrics over time (#203)
1 parent 2cb7066 commit 688ff6d

4 files changed

Lines changed: 204 additions & 1 deletion

File tree

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Imports:
2727
survival,
2828
utils,
2929
Rcpp,
30-
ggplot2,
30+
ggplot2 (>= 3.4.0),
3131
ggrepel,
3232
gplots,
3333
plotly,

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export(MSstatsNormalize)
1717
export(MSstatsPrepareForDataProcess)
1818
export(MSstatsPrepareForGroupComparison)
1919
export(MSstatsPrepareForSummarization)
20+
export(MSstatsQualityMetricsPlot)
2021
export(MSstatsSelectFeatures)
2122
export(MSstatsSummarizationOutput)
2223
export(MSstatsSummarizeSingleLinear)

R/plot_quality_metrics.R

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#' Plot quality metrics from converter output
2+
#'
3+
#' Visualizes a quality metric column from the output of MSstats converter
4+
#' functions against run order for a single protein. Each
5+
#' PeptideSequence + PrecursorCharge combination is drawn as a distinct
6+
#' coloured line, mirroring the feature-level view in
7+
#' \code{\link[MSstats]{dataProcessPlots}}.
8+
#'
9+
#' @param input data.frame or data.table returned by an MSstatsConvert
10+
#' converter function (e.g. \code{SpectronauttoMSstatsFormat}).
11+
#' @param metric character, name of the column to plot on the y-axis.
12+
#' Defaults to \code{"AnomalyScores"}. Must be a column of \code{input}.
13+
#' @param which.Protein character, name of the protein to plot. Required.
14+
#' @param address prefix for the filename used when saving the plot.
15+
#' If \code{FALSE} (default), the plot is returned without saving.
16+
#' When \code{isPlotly = FALSE} a PDF is saved; when \code{isPlotly = TRUE}
17+
#' an HTML file is saved.
18+
#' @param isPlotly logical. If \code{TRUE} returns an interactive
19+
#' \code{\link[plotly]{plotly}} object (and saves as HTML when
20+
#' \code{address} is provided). If \code{FALSE} (default) returns a
21+
#' \code{\link[ggplot2]{ggplot}} object.
22+
#'
23+
#' @return A \code{\link[ggplot2]{ggplot}} object, or a \code{plotly} object
24+
#' when \code{isPlotly = TRUE}.
25+
#'
26+
#' @details
27+
#' The x-axis order is determined by the factor levels of the \code{Run}
28+
#' column. When \code{runOrder} is passed to the converter the \code{Run}
29+
#' column is automatically set to an ordered factor; otherwise the runs appear
30+
#' in alphabetical order.
31+
#'
32+
#' Metric values are averaged across fragment ions within each
33+
#' PeptideSequence + PrecursorCharge + Run combination before plotting, so
34+
#' each precursor contributes exactly one point per run.
35+
#'
36+
#' @import ggplot2
37+
#' @importFrom plotly ggplotly
38+
#' @importFrom htmltools save_html
39+
#'
40+
#' @export
41+
#'
42+
#' @examples
43+
#' \dontrun{
44+
#' result <- SpectronauttoMSstatsFormat(
45+
#' input, calculateAnomalyScores = TRUE,
46+
#' anomalyModelFeatures = c("FGShapeQualityScoreMS2", "EGDeltaRT"),
47+
#' anomalyModelFeatureTemporal = c("mean_decrease", "dispersion_increase"),
48+
#' runOrder = my_run_order
49+
#' )
50+
#' MSstatsQualityMetricsPlot(result, which.Protein = "ProteinA")
51+
#' MSstatsQualityMetricsPlot(result, metric = "EGDeltaRT",
52+
#' which.Protein = "ProteinA", isPlotly = TRUE)
53+
#' }
54+
MSstatsQualityMetricsPlot <- function(input, metric = "AnomalyScores",
55+
which.Protein,
56+
address = FALSE, isPlotly = FALSE) {
57+
if (missing(which.Protein)) {
58+
stop("'which.Protein' is required. Please specify a protein name.")
59+
}
60+
61+
input_df <- as.data.frame(input)
62+
63+
required_cols <- c("ProteinName", "PeptideSequence", "PrecursorCharge", "Run")
64+
missing_cols <- setdiff(required_cols, colnames(input_df))
65+
if (length(missing_cols) > 0) {
66+
stop(paste0(
67+
"Required column(s) not found in input: ",
68+
paste(missing_cols, collapse = ", ")
69+
))
70+
}
71+
if (!metric %in% colnames(input_df)) {
72+
stop(paste0(
73+
"Column '", metric, "' not found in input. ",
74+
"Available columns: ", paste(colnames(input_df), collapse = ", ")
75+
))
76+
}
77+
if (!which.Protein %in% input_df$ProteinName) {
78+
stop(paste0("Protein '", which.Protein, "' not found in input."))
79+
}
80+
81+
input_df <- input_df[input_df$ProteinName == which.Protein, ]
82+
83+
if (!is.factor(input_df$Run)) {
84+
input_df$Run <- factor(input_df$Run)
85+
}
86+
87+
input_df$Precursor <- paste(input_df$PeptideSequence,
88+
input_df$PrecursorCharge, sep = "_")
89+
90+
# Average across fragment ions so each precursor has one value per run
91+
plot_df <- aggregate(
92+
input_df[[metric]],
93+
by = list(Run = input_df$Run, Precursor = input_df$Precursor),
94+
FUN = mean, na.rm = TRUE
95+
)
96+
colnames(plot_df)[colnames(plot_df) == "x"] <- metric
97+
98+
# Preserve run factor ordering from the original data
99+
plot_df$Run <- factor(plot_df$Run, levels = levels(input_df$Run))
100+
101+
p <- ggplot(plot_df,
102+
aes(x = .data[["Run"]],
103+
y = .data[[metric]],
104+
color = .data[["Precursor"]],
105+
group = .data[["Precursor"]])) +
106+
geom_line(linewidth = 0.6) +
107+
geom_point(size = 1.5) +
108+
scale_x_discrete(guide = guide_axis(angle = 45)) +
109+
theme_bw() +
110+
theme(axis.text.x = element_text(size = 8),
111+
legend.title = element_text(size = 9),
112+
legend.text = element_text(size = 7)) +
113+
labs(x = "Run (temporal order)",
114+
y = metric,
115+
title = paste("Quality Metric:", metric),
116+
subtitle = which.Protein,
117+
color = "Peptide_Charge")
118+
119+
if (isPlotly) {
120+
plotly_p <- ggplotly(p)
121+
if (!identical(address, FALSE)) {
122+
save_html(plotly_p,
123+
file = paste0(address, "QualityMetricsPlot.html"))
124+
}
125+
return(plotly_p)
126+
}
127+
128+
if (!identical(address, FALSE)) {
129+
pdf(paste0(address, "QualityMetricsPlot.pdf"))
130+
print(p)
131+
dev.off()
132+
}
133+
134+
p
135+
}

man/MSstatsQualityMetricsPlot.Rd

Lines changed: 67 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)