1111# ' across (samples and) reads before plotting. Must be one of "none" (no
1212# ' aggregation, individual values from the assay are plotted) and "mean"
1313# ' (calculate average value for each position before plotting).
14+ # ' @param selectContextsBy Character scalar indicating how to select and order
15+ # ' the contexts to show in the plot. Should be one of \code{"sample"} (in
16+ # ' which case the selection of sequence contexts will be done independently
17+ # ' for each sample, and only the ones selected for a given sample will
18+ # ' be displayed in the plot panel for that sample; in this case
19+ # ' \code{facetBy} must be \code{"sample"}), \code{"sample_union"} (
20+ # ' in which case the selection of sequence contexts will be done for each
21+ # ' sample, and the union of all selected contexts will be shown in the
22+ # ' plot) or \code{"overall"} (in which case the selection of sequence
23+ # ' contexts will be made without considering the sample information). Note
24+ # ' that for \code{"sample_union"}, the plots may contain more than
25+ # ' \code{topN + bottomN} contexts. For \code{"sample_union"} and
26+ # ' \code{"overall"}, the order of the contexts in the plots will be
27+ # ' determined by the average value across samples).
1428# ' @param facetBy Character scalar indicating how to facet values in the plot.
1529# ' Must be either \code{NULL} (in which case no facetting is done, and
1630# ' values are aggregated across all samples in \code{se}) or \code{"sample"}
1731# ' (in which case values are aggregated within each sample, and plots are
1832# ' facetted accordingly).
1933# ' @param plotType Character scalar indicating what type of plot to create.
20- # ' Should be one of \code{"violin"}, \code{"bar"} and \code{"errorbar"}.
34+ # ' Should be one of \code{"violin"} (note that the violins will be plotted
35+ # ' with \code{scale="width"}), \code{"bar"} and \code{"errorbar"}.
2136# ' @param topN,bottomN Numeric scalars determining the number of sequence
2237# ' contexts to include in the plot. The \code{topN} contexts with the
2338# ' highest average values and the \code{bottomN} contexts with the lowest
5267# ' topN = 3, bottomN = 3, facetBy = "sample")
5368# '
5469# ' @importFrom dplyr group_by mutate ungroup arrange desc select distinct
55- # ' bind_rows slice_max slice_min filter summarize
70+ # ' bind_rows slice_max slice_min filter summarize inner_join
5671# ' @importFrom SummarizedExperiment rowData assay colnames assayNames
5772# ' @importFrom ggplot2 ggplot aes geom_violin theme_bw geom_col geom_linerange
5873# ' geom_errorbar coord_flip
@@ -65,6 +80,7 @@ plotValsBySeqContext <- function(se,
6580 seqContextColumn = " sequenceContext" ,
6681 assayName = " mod_prob" ,
6782 aggregation = " mean" ,
83+ selectContextsBy = " sample_union" ,
6884 facetBy = NULL ,
6985 plotType = " violin" ,
7086 topN = 10 ,
@@ -77,83 +93,133 @@ plotValsBySeqContext <- function(se,
7793 validValues = colnames(rowData(se )))
7894 .assertScalar(x = aggregation , type = " character" ,
7995 validValues = c(" none" , " mean" ))
80- .assertScalar(x = assayName , type = " character" ,
81- validValues = .getReadLevelAssayNames(se ))
8296 .assertScalar(x = facetBy , type = " character" , validValues = " sample" ,
8397 allowNULL = TRUE )
98+ if (is.null(facetBy )) {
99+ .assertScalar(x = selectContextsBy , type = " character" ,
100+ validValues = c(" sample_union" , " overall" ))
101+ } else {
102+ .assertScalar(x = selectContextsBy , type = " character" ,
103+ validValues = c(" sample" , " sample_union" , " overall" ))
104+ }
105+ .assertScalar(x = assayName , type = " character" ,
106+ validValues = .getReadLevelAssayNames(se ))
84107 .assertScalar(x = plotType , type = " character" ,
85108 validValues = c(" violin" , " bar" , " errorbar" ))
86109 .assertScalar(x = topN , type = " numeric" , rngIncl = c(0 , Inf ))
87110 .assertScalar(x = bottomN , type = " numeric" , rngIncl = c(0 , Inf ))
88111 .assertScalar(x = flipCoord , type = " logical" )
89112 .assertScalar(x = yAxisLabel , type = " character" )
90113
91- # calculate plot values
92- if (aggregation == " mean" & is.null(facetBy )) {
93- a <- as.matrix(assay(se , assayName ))
94- df <- data.frame (sample = " 1" ,
95- seqContext = rowData(se )[[seqContextColumn ]],
96- vals = rowSums(a , na.rm = TRUE ) / rowSums(is_nonna(a ))) | >
97- # remove positions with all NA values (could happen e.g. if the input
98- # se is obtained by subsetting an se with more samples)
99- dplyr :: filter(! is.na(.data $ vals ))
100- } else if (aggregation == " none" & is.null(facetBy )) {
101- a <- as.matrix(assay(se , assayName ))
102- nna <- nnawhich(a , arr.ind = TRUE )
103- nnav <- nnavals(a )
104- df <- data.frame (sample = " 1" ,
105- seqContext = rowData(se )[[seqContextColumn ]][nna [, 1 ]],
106- vals = nnav )
107- } else if (aggregation == " mean" & facetBy == " sample" ) {
108- df <- do.call(bind_rows , lapply(colnames(se ), function (cn ) {
109- a <- assay(se , assayName )[[cn ]]
110- data.frame (sample = cn ,
111- seqContext = rowData(se )[[seqContextColumn ]],
112- vals = rowSums(a , na.rm = TRUE ) / rowSums(is_nonna(a )))
113- })) | >
114- dplyr :: filter(! is.na(.data $ vals ))
115- } else if (aggregation == " none" & facetBy == " sample" ) {
116- df <- do.call(bind_rows , lapply(colnames(se ), function (cn ) {
117- a <- assay(se , assayName )[[cn ]]
114+ # calculate plot/selection values
115+ # ... global ones (required if either facetBy = NULL or selectContextsBy = "overall")
116+ if (is.null(facetBy ) || selectContextsBy == " overall" ) {
117+ if (aggregation == " mean" ) {
118+ a <- as.matrix(assay(se , assayName ))
119+ dfGlobal <- data.frame (sample = " overall" ,
120+ seqContext = rowData(se )[[seqContextColumn ]],
121+ vals = rowSums(a , na.rm = TRUE ) / rowSums(is_nonna(a ))) | >
122+ # remove positions with all NA values (could happen e.g. if the input
123+ # se is obtained by subsetting an se with more samples)
124+ dplyr :: filter(! is.na(.data $ vals ))
125+ } else if (aggregation == " none" ) {
126+ a <- as.matrix(assay(se , assayName ))
118127 nna <- nnawhich(a , arr.ind = TRUE )
119128 nnav <- nnavals(a )
120- data.frame (sample = cn ,
121- seqContext = rowData(se )[[seqContextColumn ]][nna [, 1 ]],
122- vals = nnav )
123- }))
129+ dfGlobal <- data.frame (sample = " overall" ,
130+ seqContext = rowData(se )[[seqContextColumn ]][nna [, 1 ]],
131+ vals = nnav )
132+ }
133+ }
134+
135+ # ... sample-wise ones (required if either facetBy = "sample" or
136+ # selectContextsBy = "sample" or "sample_union")
137+ if ((! is.null(facetBy ) && facetBy == " sample" ) ||
138+ selectContextsBy %in% c(" sample" , " sample_union" )) {
139+ if (aggregation == " mean" ) {
140+ dfSample <- do.call(bind_rows , lapply(colnames(se ), function (cn ) {
141+ a <- assay(se , assayName )[[cn ]]
142+ data.frame (sample = cn ,
143+ seqContext = rowData(se )[[seqContextColumn ]],
144+ vals = rowSums(a , na.rm = TRUE ) / rowSums(is_nonna(a )))
145+ })) | >
146+ dplyr :: filter(! is.na(.data $ vals ))
147+ } else if (aggregation == " none" ) {
148+ dfSample <- do.call(bind_rows , lapply(colnames(se ), function (cn ) {
149+ a <- assay(se , assayName )[[cn ]]
150+ nna <- nnawhich(a , arr.ind = TRUE )
151+ nnav <- nnavals(a )
152+ data.frame (sample = cn ,
153+ seqContext = rowData(se )[[seqContextColumn ]][nna [, 1 ]],
154+ vals = nnav )
155+ }))
156+ }
124157 }
125- df $ flipCoord <- flipCoord
158+
159+ # choose data frames to use for selection/plotting
160+ if (selectContextsBy %in% c(" sample" , " sample_union" )) {
161+ dfSel <- dfSample
162+ } else {
163+ dfSel <- dfGlobal
164+ }
165+
166+ if (is.null(facetBy )) {
167+ dfPlot <- dfGlobal
168+ } else {
169+ dfPlot <- dfSample
170+ }
171+
172+ dfPlot $ flipCoord <- flipCoord
126173
127174 # calculate mean/sd for each context and select top/bottom ones to include
128- dfsum <- df | >
129- group_by(.data $ seqContext , .data $ sample , .data $ flipCoord ) | >
175+ dfSelSum <- dfSel | >
176+ group_by(.data $ seqContext , .data $ sample ) | >
130177 summarize(valsMean = mean(.data $ vals ),
131- valsSd = sd(.data $ vals ),
132178 .groups = " drop" )
133- dfsum <- bind_rows(
134- dfsum | > group_by(sample ) | >
179+ dfSelSum <- bind_rows(
180+ dfSelSum | > group_by(sample ) | >
135181 slice_max(.data $ valsMean , n = topN , with_ties = FALSE ),
136- dfsum | > group_by(sample ) | >
182+ dfSelSum | > group_by(sample ) | >
137183 slice_min(.data $ valsMean , n = bottomN , with_ties = FALSE )
138184 ) | >
139185 ungroup() | >
140186 distinct()
141187
188+ # Subset dfPlot for plotting
189+ # If selectContextsBy = "sample", need to keep the link between sample and
190+ # context. Otherwise, the union of the selected contexts should all be
191+ # selected for all samples in dfPlot
192+ if (selectContextsBy == " sample" ) {
193+ # here we know that facetBy = "sample"
194+ dfPlot <- dfPlot | >
195+ inner_join(dfSelSum , by = c(" sample" , " seqContext" )) | >
196+ mutate(orderCol = .data $ sample )
197+ } else {
198+ contextsToKeep <- unique(dfSelSum $ seqContext )
199+ dfPlot <- dfPlot | >
200+ dplyr :: filter(seqContext %in% contextsToKeep ) | >
201+ mutate(orderCol = " overall" )
202+ }
203+
142204 # plot
143205 if (plotType == " violin" ) {
144- df <- df | >
145- dplyr :: filter(.data $ seqContext %in% dfsum $ seqContext ) | >
206+ dfPlot <- dfPlot | >
146207 mutate(seqContext = reorder_within(.data $ seqContext , by = ifelse(
147208 .data $ flipCoord , .data $ vals , - .data $ vals ),
148- within = sample , fun = mean ))
149- gg <- ggplot(df , aes(x = .data $ seqContext , y = .data $ vals )) +
209+ within = orderCol , fun = mean ))
210+ gg <- ggplot(dfPlot , aes(x = .data $ seqContext , y = .data $ vals )) +
150211 geom_violin(scale = " width" )
151212 } else if (plotType %in% c(" bar" , " errorbar" )) {
152- dfsum <- dfsum | >
213+ dfPlot <- dfPlot | >
214+ group_by(.data $ seqContext , .data $ sample , .data $ orderCol ,
215+ .data $ flipCoord ) | >
216+ summarize(valsMean = mean(.data $ vals ),
217+ valsSd = sd(.data $ vals ),
218+ .groups = " drop" ) | >
153219 mutate(seqContext = reorder_within(.data $ seqContext , by = ifelse(
154220 .data $ flipCoord , .data $ valsMean , - .data $ valsMean ),
155- within = sample , fun = mean ))
156- gg <- ggplot(dfsum ,
221+ within = orderCol , fun = mean ))
222+ gg <- ggplot(dfPlot ,
157223 aes(x = .data $ seqContext , y = .data $ valsMean )) +
158224 geom_col()
159225 if (plotType == " errorbar" ) {
0 commit comments