-
Notifications
You must be signed in to change notification settings - Fork 2
New fun compare cel pop #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
50 commits
Select commit
Hold shift + click to select a range
e65e284
UsingClaude added Compare_Cell_Pop from NIDAPjson. passed AI tests
phoman14 ec5d485
fixing ModScoreHelpers_function. Error with Roxygen Format
phoman14 c3c6152
Update Vignette
phoman14 d5579ff
Update Vignette for MS app
phoman14 1d015eb
Start CompareCelPop Vignette
phoman14 1fe0144
Add code for compareCellPopulations Vignette
phoman14 0c49ece
add Vis_CCPbar.png
phoman14 1524b4f
Render Visualizations.Rmd with pkgdown
phoman14 ea28d75
resize CCPbar figure for vignette
phoman14 7083428
Add CCPbox to Vignette
phoman14 b9773d1
Add description for Compare Cell populations
phoman14 1d82e29
Merge branch 'NewFun_CompareCelPop' of https://github.com/NIDAP-Commu…
phoman14 2783ae0
edit CCP function description in vignette
phoman14 b14c72f
modify ViolinPlot function name and add standard output
phoman14 782eb25
change violin plot name for tests violinPlot_mod -> violinPlot
phoman14 34bd002
Build Vignettes with updates
phoman14 d0118bf
Modify _pkgdown.yml and /Vignevignettes/README.Rmd -> vignettes/Intro…
phoman14 0e58060
Reverting Intro.Rmd to README.Rmd
phoman14 de058fe
tried to troubleshoot running vignetts with devtools::check(). did no…
phoman14 51e02ed
rmeove Intro.Rmd after changed to README.Rmd
phoman14 0cee2ac
add htmlttols for Vignettes
phoman14 e739ff8
LOCAL: tried to troubleshoot running vignetts with devtools::check().…
phoman14 0147b28
Merge branch 'NewFun_CompareCelPop' of https://github.com/NIDAP-Commu…
phoman14 523b295
Modifications to pass unit tests
phoman14 5e86dd3
update vignette to use README.Rmd not Intro.Rmd
phoman14 e2a513e
Potential fix for pull request finding
phoman14 cbebbdc
added Vignette docs folder
phoman14 a928f09
Merge branch 'NewFun_CompareCelPop' of https://github.com/NIDAP-Commu…
phoman14 c6a8037
remvoed metadata.table from Compare_cell_Populations.R because no log…
phoman14 e0be21c
Initial plan
Copilot 946b476
Add else-stop to getParamCCP for unknown data values
Copilot 426988b
Initial plan
Copilot 170e50c
Add else branch to getParamCCP() with stop() for unknown datasets
Copilot 6b85231
adding an explicit else that stop()s with a clear message listing the…
phoman14 5329bf9
remove sptatstat.corre from DESCRIPTION
phoman14 6bdcbc7
Merge branch 'NewFun_CompareCelPop' into copilot/sub-pr-80
phoman14 e13dc63
Merge pull request #81 from NIDAP-Community/copilot/sub-pr-80
phoman14 0f1d9df
Merge branch 'NewFun_CompareCelPop' into copilot/sub-pr-80-again
phoman14 5f1bc23
Merge pull request #82 from NIDAP-Community/copilot/sub-pr-80-again
phoman14 4eee8fc
removed htmltools from DESCRIPTION
phoman14 62ea9b8
Deleted docs/reference/violinPlot_mod.html
phoman14 ad367d7
Potential fix for pull request finding
phoman14 4452608
Potential fix for pull request finding
phoman14 c152b3b
Initial plan
Copilot 8c18f46
Fix trailing comma in knitr chunk header in SCWorkflow-Visualizations…
Copilot 620f2de
Merge pull request #83 from NIDAP-Community/copilot/sub-pr-80-another…
phoman14 c2f945d
Potential fix for pull request finding
phoman14 a709130
Potential fix for pull request finding
phoman14 8d4a31b
Run Tests after copiolot modifications
phoman14 81353a3
Potential fix for pull request finding
phoman14 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,3 +5,5 @@ | |
| ^Dockerfile$ | ||
| ^Dockerfiles/.*$ | ||
| ^Conda_Recipe/.*$ | ||
| ^doc$ | ||
| ^Meta$ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ tests/testthat/output/ | |
|
|
||
| inst/doc | ||
| #inst/extdata/* | ||
| docs | ||
| *.Rds | ||
| *.rds | ||
| /doc/ | ||
| /Meta/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,263 @@ | ||
| #' @title Compare Cell Populations | ||
| #' @description Compare cell population distributions across different groups | ||
| #' using bar plots and box plots. Creates visualizations showing cell type | ||
| #' frequencies or counts across user-defined groupings. | ||
| #' | ||
| #' @details This function generates comparative visualizations of cell | ||
| #' populations from a Seurat object. It can display data as either frequency | ||
| #' percentages or absolute counts, and creates both stacked bar plots | ||
| #' (with alluvial flow connections) and grouped box plots for comparison | ||
| #' across samples and conditions. | ||
| #' | ||
| #' @param object A Seurat object containing the single-cell data | ||
| #' @param annotation.column Character string specifying the metadata column | ||
| #' containing cell type annotations to summarize in the bar plot | ||
| #' @param group.column Character string specifying the metadata column | ||
| #' defining groups to compare (e.g., treatment conditions) | ||
| #' @param sample.column Character string specifying the metadata column | ||
| #' containing sample identifiers. Default is "orig.ident" | ||
| #' @param counts.type Character string specifying plot data type: | ||
| #' "Frequency" (percentages) or "Counts" (absolute numbers). Default is "Frequency" | ||
| #' @param group.order Character vector specifying the order of groups in plots. | ||
| #' If NULL, uses natural order from data. Default is NULL | ||
| #' @param seurat.object.filename Character string for the Seurat object | ||
| #' filename. Default is "seurat_object.rds" | ||
| #' @param wrap.ncols Integer specifying number of columns for facet wrapping | ||
| #' in box plots. Default is 5 | ||
| #' | ||
| #' @import Seurat | ||
| #' @import ggplot2 | ||
| #' @import ggpubr | ||
| #' @import RColorBrewer | ||
| #' @import tibble | ||
| #' @import reshape2 | ||
| #' @import data.table | ||
| #' @import dplyr | ||
| #' @import magrittr | ||
| #' @import cowplot | ||
| #' @import gridExtra | ||
| #' @import grid | ||
| #' @import scales | ||
| #' | ||
| #' @importFrom ggalluvial geom_flow | ||
| #' @importFrom stats setNames | ||
| #' @importFrom grDevices colorRampPalette | ||
| #' | ||
| #' @export | ||
| #' | ||
| #' @return A list containing: | ||
| #' \itemize{ | ||
| #' \item \code{Plots} - A list with two ggplot objects: | ||
| #' \itemize{ | ||
| #' \item \code{Barplot} - Stacked bar plot with alluvial flows | ||
| #' \item \code{Boxplot} - Faceted box plots by cell type (only if counts.type="Frequency") | ||
| #' } | ||
| #' \item \code{Table} - A data.frame with cell counts and percentages | ||
| #' } | ||
| #' | ||
| #' @examples | ||
| #' \dontrun{ | ||
| #' # Compare cell populations by treatment group | ||
| #' results <- compareCellPopulations( | ||
| #' object = seurat_obj, | ||
| #' annotation.column = "cell_type", | ||
| #' group.column = "treatment", | ||
| #' sample.column = "sample_id", | ||
| #' counts.type = "Frequency" | ||
| #' ) | ||
| #' | ||
| #' # Display plots | ||
| #' plot(results$Plots$Barplot) | ||
| #' plot(results$Plots$Boxplot) | ||
| #' | ||
| #' # View summary table | ||
| #' head(results$Table) | ||
| #' } | ||
|
|
||
| compareCellPopulations <- function( | ||
| object, | ||
| annotation.column, | ||
| group.column, | ||
| sample.column = "orig.ident", | ||
| counts.type = "Frequency", | ||
| group.order = NULL, | ||
| wrap.ncols = 5 | ||
| ) { | ||
phoman14 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ## -------------------------------- ## | ||
| ## Input Validation ## | ||
| ## -------------------------------- ## | ||
|
|
||
| # Validate object | ||
| if (!inherits(object, "Seurat")) { | ||
| stop("Error: 'object' must be a Seurat object") | ||
| } | ||
|
|
||
| # Validate counts.type | ||
| if (!counts.type %in% c("Frequency", "Counts")) { | ||
| stop("Error: 'counts.type' must be either 'Frequency' or 'Counts'") | ||
| } | ||
|
|
||
| ## --------- ## | ||
| ## Functions ## | ||
| ## --------- ## | ||
|
|
||
| createAnnoTable <- function(SO, AnnoCol, GroupCol) { | ||
| ## Extract annotation data for each group using a 2D contingency table | ||
| cntMat <- table(SO@meta.data[[AnnoCol]], SO@meta.data[[GroupCol]]) | ||
|
|
||
| # Convert to data frame while preserving row/column names | ||
| cntTble <- as.data.frame.matrix(cntMat) | ||
| cntTble <- data.frame( | ||
| lapply(cntTble, function(x) as.numeric(as.character(x))), | ||
| check.names = FALSE, | ||
| row.names = rownames(cntTble) | ||
| ) | ||
|
|
||
| freqTble <- apply(cntTble, 2, FUN = function(x) { | ||
| return(x / sum(x)) | ||
| }) | ||
| freqTble <- (freqTble * 100) | ||
|
|
||
| outTbl <- merge(cntTble, as.data.frame(freqTble), | ||
| by = 'row.names', | ||
| suffixes = c('_CellCounts', '_Percent')) | ||
| outTbl <- dplyr::rename(outTbl, 'Clusters' = "Row.names") | ||
|
|
||
| return(list( | ||
| 'CellFreq' = freqTble, | ||
| 'CellCounts' = cntTble, | ||
| 'OutTable' = outTbl | ||
| )) | ||
| } | ||
|
|
||
| ## --------------- ## | ||
| ## Main Code Block ## | ||
| ## --------------- ## | ||
|
|
||
| # Replace dots with underscores in column names | ||
| colnames(object@meta.data) <- gsub("\\.", "_", colnames(object@meta.data)) | ||
|
|
||
| # Update column names if they were modified | ||
| annotation.column <- gsub("\\.", "_", annotation.column) | ||
| group.column <- gsub("\\.", "_", group.column) | ||
| sample.column <- gsub("\\.", "_", sample.column) | ||
|
|
||
|
|
||
| # Validate metadata columns exist | ||
| required.cols <- c(annotation.column, group.column, sample.column) | ||
| missing.cols <- setdiff(required.cols, colnames(object@meta.data)) | ||
| if (length(missing.cols) > 0) { | ||
| stop("Error: The following columns are missing from metadata: ", | ||
| paste(missing.cols, collapse = ", ")) | ||
| } | ||
|
|
||
|
|
||
|
|
||
|
|
||
| # Set up ordering | ||
| ordr <- object@meta.data[[annotation.column]] %>% | ||
| unique() %>% | ||
| sort() | ||
|
|
||
| if (is.null(group.order)) { | ||
| group.order <- unique(object@meta.data[[group.column]]) | ||
| } | ||
|
|
||
| # Set up colors | ||
| numColors <- max( | ||
| length(unique(object@meta.data[[annotation.column]])), | ||
| 20 | ||
| ) | ||
| colpaired <- colorRampPalette(brewer.pal(12, "Paired")) | ||
| cols <- c( | ||
| "#e6194B", "#3cb44b", "#4363d8", "#f58231", "#911eb4", "#42d4f4", | ||
| "#f032e6", "#bfef45", "#fabebe", "#469990", "#e6beff", "#9A6324", | ||
| "#800000", "#aaffc3", "#808000", "#000075", | ||
| colpaired(numColors) | ||
| ) | ||
phoman14 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| names(cols) <- ordr | ||
|
|
||
| object@meta.data[[annotation.column]] <- factor( | ||
| object@meta.data[[annotation.column]], | ||
| levels = ordr | ||
| ) | ||
|
|
||
| # Create tables | ||
| ColTables <- createAnnoTable(object, annotation.column, group.column) | ||
| BoxTables <- createAnnoTable(object, annotation.column, sample.column) | ||
|
|
||
| metaGroups <- object@meta.data[, c(group.column, sample.column)] | ||
| rownames(metaGroups) <- NULL | ||
| metaGroups <- metaGroups %>% unique() | ||
|
|
||
| ## Create plots based on counts type | ||
| if (counts.type == 'Frequency') { | ||
| ptbl <- melt(ColTables$CellFreq) | ||
| ptblBox <- melt(as.matrix(BoxTables$CellFreq)) | ||
| ptblBox <- merge(ptblBox, metaGroups, | ||
| by.x = 'Var2', by.y = sample.column, all.x = TRUE) | ||
|
|
||
| labelCol <- 'PerValue' | ||
| ylab <- 'Frequency of each cell type (100%)' | ||
| } else if (counts.type == "Counts") { | ||
| ptbl <- melt(as.matrix(ColTables$CellCounts)) | ||
| ptblBox <- melt(as.matrix(BoxTables$CellCounts)) | ||
| ptblBox <- merge(ptblBox, metaGroups, | ||
| by.x = 'Var2', by.y = sample.column, all.x = TRUE) | ||
|
|
||
| labelCol <- 'value' | ||
| ylab <- 'Cell Counts' | ||
| } | ||
|
|
||
| # Format bar plot data | ||
| ptbl$Var1 <- factor(ptbl$Var1, levels = ordr) | ||
| ptbl$value <- round(ptbl$value, 1) | ||
| ptbl$PerValue <- paste0(ptbl$value, '%') | ||
| ptbl$PerValue <- gsub('^%$', "_", ptbl$PerValue) | ||
| ptbl[ptbl$value < 1, 'PerValue'] <- "" | ||
| ptbl$Var2 <- factor(ptbl$Var2, levels = group.order) | ||
|
|
||
| # Create bar plot with alluvial flows | ||
| p2 <- ptbl %>% | ||
| ggplot(aes_string(y = 'value', x = 'Var2', fill = 'Var1', label = labelCol)) + | ||
| geom_flow(aes(alluvium = Var1), alpha = .2, | ||
| lty = 2, color = "black", | ||
| curve_type = "linear", | ||
| width = .5) + | ||
| geom_col(aes(fill = Var1), width = .5, color = "black") + | ||
| geom_text(size = 3, position = position_stack(vjust = 0.5)) + | ||
| theme_classic() + | ||
| ylab(ylab) + | ||
| xlab("") + | ||
| scale_x_discrete(guide = guide_axis(angle = 45)) + | ||
| scale_fill_manual(annotation.column, values = cols) | ||
|
|
||
| # Create box plot | ||
| ptblBox$value <- round(ptblBox$value, 1) | ||
| ptblBox$PerValue <- paste0(ptblBox$value, '%') | ||
| ptblBox$PerValue <- gsub('^%$', "_", ptblBox$PerValue) | ||
| ptblBox[ptblBox$value < 1, 'PerValue'] <- "" | ||
| ptblBox[[group.column]] <- factor(ptblBox[[group.column]], levels = group.order) | ||
|
|
||
| p2_Box <- ptblBox %>% | ||
| ggboxplot(y = 'value', x = group.column, add = "jitter", color = "Var1") + | ||
| facet_wrap(~Var1, ncol = wrap.ncols, scales = 'fixed') + | ||
| ylab(ylab) + | ||
| xlab("") + | ||
| theme(legend.title = element_blank()) | ||
|
|
||
| # Return results | ||
| result <- list( | ||
| 'Plots' = list('Barplot' = p2, 'Boxplot' = p2_Box), | ||
| 'Table' = ColTables$OutTable | ||
| ) | ||
|
|
||
| return(result) | ||
| } | ||
|
|
||
| # Add global variables to avoid R CMD check NOTEs | ||
| utils::globalVariables(c( | ||
| "Var1", "Var2", "value", "PerValue", "alluvium", | ||
| ".", "CellFreq", "CellCounts", "OutTable" | ||
| )) | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.