@@ -407,12 +407,12 @@ ClonalLengthPlot <- function(
407407# ' @keywords internal
408408DummyClonalScatterPlot <- function (df , title , group_by , scatter_cor , size_by , ... ) {
409409 if (nrow(df ) == 0 ) {
410- stop(" No data found for the group_by: " , group_by ,
410+ stop(" [ClonalResidencyPlot] No data found for the group_by: " , group_by ,
411411 " . Did you specify the correct 'group_by'/'groups' parameters?" )
412412 }
413413 pair <- unique(as.character(df [[group_by ]]))
414414 if (length(pair ) != 2 ) {
415- stop(" The group_by should have exactly 2 unique values." )
415+ stop(" [ClonalResidencyPlot] The group_by should have exactly 2 unique values." )
416416 }
417417
418418 exponent <- function (x ) { floor(log10(abs(x ))) }
@@ -594,7 +594,9 @@ DummyClonalScatterPlot <- function(df, title, group_by, scatter_cor, size_by, ..
594594# ' @param group_by The column name in the meta data to group the cells. Default: "Sample"
595595# ' @param groups The groups to compare. Default is NULL.
596596# ' If NULL, all the groups in `group_by` will be compared.
597- # ' Note that for "scatter" plot, only two groups can be compared.
597+ # ' Note that for "scatter" plot, only two groups can be compared. So when there are more than two groups,
598+ # ' the combination of the pairs will be used.
599+ # ' For "scatter" plot, the groups can be specified as the comparisons separated by ":", e.g. "L:B", "Y:X".
598600# ' @param facet_by The column name in the meta data to facet the plots. Default: NULL
599601# ' @param split_by The column name in the meta data to split the plots. Default: NULL
600602# ' @param split_by_sep The separator used to concatenate the split_by when multiple columns are used.
@@ -616,7 +618,7 @@ DummyClonalScatterPlot <- function(df, title, group_by, scatter_cor, size_by, ..
616618# ' @return A ggplot object or a list if `combine` is FALSE
617619# ' @export
618620# ' @importFrom utils combn
619- # ' @importFrom dplyr distinct rename_with select across starts_with ends_with
621+ # ' @importFrom dplyr distinct rename_with select across starts_with ends_with %>% filter
620622# ' @importFrom tidyr pivot_longer separate pivot_wider unite
621623# ' @importFrom scRepertoire clonalScatter
622624# ' @importFrom plotthis ScatterPlot VennDiagram UpsetPlot
@@ -628,17 +630,20 @@ DummyClonalScatterPlot <- function(df, title, group_by, scatter_cor, size_by, ..
628630# ' samples = c("P17B", "P17L", "P18B", "P18L", "P19B","P19L", "P20B", "P20L"))
629631# ' data <- scRepertoire::addVariable(data,
630632# ' variable.name = "Type",
631- # ' variables = rep(c("B", "L"), 4 )
633+ # ' variables = rep(c("B", "L", "X", "Y" ), 2 )
632634# ' )
633635# ' data <- scRepertoire::addVariable(data,
634636# ' variable.name = "Subject",
635637# ' variables = rep(c("P17", "P18", "P19", "P20"), each = 2)
636638# ' )
637639# '
638640# ' ClonalResidencyPlot(data, groups = c("P18B", "P18L"))
639- # ' ClonalResidencyPlot(data, group_by = "Type", split_by = "Subject")
640- # ' ClonalResidencyPlot(data, plot_type = "venn", groups = c("B", "L"), group_by = "Type",
641+ # ' ClonalResidencyPlot(data, group_by = "Type", groups = c("L", "B"),
642+ # ' split_by = "Subject")
643+ # ' ClonalResidencyPlot(data, group_by = "Type", groups = c("L:B", "Y:X"),
641644# ' split_by = "Subject")
645+ # ' ClonalResidencyPlot(data, plot_type = "venn", groups = c("B", "L"),
646+ # ' group_by = "Type", split_by = "Subject")
642647# ' ClonalResidencyPlot(data, plot_type = "upset", groups = c("P18B", "P18L"))
643648# ' }
644649ClonalResidencyPlot <- function (
@@ -648,8 +653,8 @@ ClonalResidencyPlot <- function(
648653 order = list (), combine = TRUE , nrow = NULL , ncol = NULL , byrow = TRUE , ...
649654) {
650655
651- stopifnot(" ClonalResidencyPlot supports only a single group_by column" = length(group_by ) == 1 )
652- stopifnot(" 'facet_by' is not supported for 'ClonalResidencyPlot' " = is.null(facet_by ))
656+ stopifnot(" [ ClonalResidencyPlot] only a single ` group_by` column supported " = length(group_by ) == 1 )
657+ stopifnot(" [ClonalResidencyPlot] 'facet_by' is not supported" = is.null(facet_by ))
653658
654659 plot_type <- match.arg(plot_type )
655660 scatter_size_by <- match.arg(scatter_size_by )
@@ -664,44 +669,69 @@ ClonalResidencyPlot <- function(
664669 }
665670 }
666671
667- groups <- groups %|| % unique(data [[group_by ]])
672+ # handle the groups
673+ # the order of groups should override the order in the data, even specified by `order`
674+ if (is.null(groups )) {
675+ if (! is.factor(data [[group_by ]])) {
676+ data [[group_by ]] <- factor (data [[group_by ]])
677+ }
678+ groups <- levels(data [[group_by ]])
679+ } else {
680+ groups <- unique(groups )
681+ if (any(grepl(" :" , groups , fixed = TRUE ))) {
682+ if (! identical(plot_type , " scatter" )) {
683+ stop(" [ClonalResidencyPlot] The 'groups' parameter should not contain ':' for non-scatter plots." )
684+ }
685+ if (! all(grepl(" :" , groups , fixed = TRUE ))) {
686+ stop(" [ClonalResidencyPlot] All 'groups' should contain ':' for scatter plot if any of them does." )
687+ }
688+ lvls <- rev(unique(rev(unlist(strsplit(groups , " :" , fixed = TRUE )))))
689+ if (any(! lvls %in% data [[group_by ]])) {
690+ stop(paste0(" [ClonalResidencyPlot] '" , paste(setdiff(lvls , data [[group_by ]]), collapse = " , " ), " ' in `groups` parameter are not present in the data." ))
691+ }
692+ data [[group_by ]] <- factor (data [[group_by ]], levels = lvls )
693+ } else {
694+ data [[group_by ]] <- factor (data [[group_by ]], levels = groups )
695+ }
696+ }
697+
668698 if (plot_type == " scatter" ) {
669699 if (! is.null(split_by )) {
670700 data <- unite(data , " .split" , split_by , sep = split_by_sep , remove = FALSE )
671701 } else {
672702 data $ .split <- " ..."
673703 }
674704 data <- split(data , data $ .split )
675- spdata <- list ()
676- if (! is.list(groups )) {
705+ if (any(grepl(" :" , groups , fixed = TRUE ))) {
706+ groups <- lapply(groups , function (g ) {
707+ gs <- strsplit(g , " :" , fixed = TRUE )[[1 ]]
708+ if (length(gs ) != 2 ) {
709+ stop(" [ClonalResidencyPlot] The 'groups' parameter should contain exactly two values separated by ':' for scatter plot." )
710+ }
711+ gs <- trimws(gs )
712+ gs
713+ })
714+ } else {
677715 groups <- as.list(as.data.frame(combn(groups , 2 , simplify = TRUE )))
678716 }
679- for (spname in names(data )) {
680- sdata <- data [[spname ]]
681- for (gp in groups ) {
682- gname <- paste(gp , collapse = " - " )
683- gname <- ifelse(identical(spname , " ..." ), gname , paste(spname , gname , sep = " : " ))
684- spdata [[gname ]] <- sdata [sdata [[group_by ]] %in% gp , , drop = FALSE ]
717+
718+ plots <- list ()
719+ for (nm in names(data )) {
720+ for (g in groups ) {
721+ d <- data [[nm ]] %> % filter(!! sym(group_by ) %in% g )
722+ if (length(unique(as.character(d [[group_by ]]))) != 2 ) {
723+ warning(paste0(" [ClonalResidencyPlot] Not both groups '" , paste(g , collapse = " , " ), " ' is not present in the data for '" , nm , " '. Skipping." ))
724+ next
725+ }
726+ d [[group_by ]] <- factor (d [[group_by ]], levels = g )
727+ plots [[length(plots ) + 1 ]] <- DummyClonalScatterPlot(d , nm , group_by , scatter_cor , scatter_size_by , ... )
685728 }
686729 }
687- if (is.null(nrow ) && is.null(ncol ) && isTRUE(byrow ) && length(groups ) > 1 && length(data ) > 1 ) {
688- nrow <- length(data )
689- }
690- data <- spdata
691- rm(spdata )
692- } else {
693- groups <- unique(unlist(groups ))
694- }
695-
696- if (plot_type == " scatter" ) {
697- plots <- lapply(names(data ), function (nm ) {
698- DummyClonalScatterPlot(data [[nm ]], nm , group_by , scatter_cor , scatter_size_by , ... )
699- })
700730
701731 combine_plots(plots , combine = combine , nrow = nrow , ncol = ncol , byrow = byrow )
702732 } else if (plot_type == " venn" ) {
703733 if (length(groups ) > 4 ) {
704- stop(" Too many groups for venn plot. Please use 'upset' plot instead." )
734+ stop(" [ClonalResidencyPlot] Too many groups for venn plot. Please use 'upset' plot instead." )
705735 }
706736 data <- data [data [[group_by ]] %in% groups , , drop = FALSE ]
707737 data <- data [data $ count > 0 , , drop = FALSE ]
0 commit comments