Last updated: 2025-11-11
Checks: 7 0
Knit directory: dge-analysis/
This reproducible R Markdown analysis was created with workflowr (version 1.7.1). The Checks tab describes the reproducibility checks that were applied when the results were created. The Past versions tab lists the development history.
Great! Since the R Markdown file has been committed to the Git repository, you know the exact version of the code that produced these results.
Great job! The global environment was empty. Objects defined in the global environment can affect the analysis in your R Markdown file in unknown ways. For reproduciblity it’s best to always run the code in an empty environment.
The command set.seed(20230618) was run prior to running
the code in the R Markdown file. Setting a seed ensures that any results
that rely on randomness, e.g. subsampling or permutations, are
reproducible.
Great job! Recording the operating system, R version, and package versions is critical for reproducibility.
Nice! There were no cached chunks for this analysis, so you can be confident that you successfully produced the results during this run.
Great job! Using relative paths to the files within your workflowr project makes it easier to run your code on other machines.
Great! You are using Git for version control. Tracking code development and connecting the code version to the results is critical for reproducibility.
The results in this page were generated with repository version 17c660d. See the Past versions tab to see a history of the changes made to the R Markdown and HTML files.
Note that you need to be careful to ensure that all relevant files for
the analysis have been committed to Git prior to generating the results
(you can use wflow_publish or
wflow_git_commit). workflowr only checks the R Markdown
file, but you know if there are other scripts or data files that it
depends on. Below is the status of the Git repository when the results
were generated:
Ignored files:
Ignored: .DS_Store
Ignored: .Rhistory
Ignored: .Rproj.user/
Ignored: .github/.DS_Store
Ignored: dge-analysis/.DS_Store
Ignored: dge-analysis/.Rhistory
Ignored: dge-analysis/.Rproj.user/
Ignored: dge-analysis/analysis/.DS_Store
Ignored: dge-analysis/data/.DS_Store
Ignored: dge-analysis/docs/.DS_Store
Ignored: dge-analysis/docs/figure/.DS_Store
Ignored: dge-analysis/docs/site_libs/.DS_Store
Ignored: dge-analysis/output/.DS_Store
Ignored: dge-analysis/output/all-samples-analysis/all-condition-analysis.RData
Ignored: dge-analysis/output/publication-analysis/publication-analysis.RData
Ignored: dge-analysis/output/spta1-analysis/batch-correction-limma/
Ignored: dge-analysis/output/subgroup-hpp-analysis/HPP-subgroup-analysis.RData
Ignored: dge-analysis/renv/.DS_Store
Ignored: dge-analysis/renv/library/
Ignored: dge-analysis/renv/staging/
Ignored: phenotypic-analysis/.DS_Store
Ignored: phenotypic-analysis/notebooks/.DS_Store
Unstaged changes:
Modified: .gitignore
Deleted: dge-analysis/docs/custom.css
Modified: dge-analysis/output/all-samples-analysis/analysis-volcano-plot.png
Modified: dge-analysis/output/all-samples-analysis/batch-correction-limma/plot-counts/madd-genes-of-interest/CYTH2-plot-counts.png
Modified: dge-analysis/output/all-samples-analysis/batch-correction-limma/plot-counts/padj-05/faceted_significant_degs_plot_counts.png
Modified: dge-analysis/output/all-samples-analysis/counts_vst.csv
Modified: dge-analysis/output/all-samples-analysis/counts_vst_limma.csv
Modified: dge-analysis/output/all-samples-analysis/madd_genes_of_interest.csv
Modified: dge-analysis/output/all-samples-analysis/mito_genes_of_interest.csv
Modified: dge-analysis/output/all-samples-analysis/other_genes_of_interest.csv
Modified: dge-analysis/output/all-samples-analysis/res_aff_vs_unaff.csv
Modified: dge-analysis/output/all-samples-analysis/res_aff_vs_unaff_df_genename.csv
Modified: dge-analysis/output/all-samples-analysis/res_aff_vs_unaff_significant_mygene.csv
Modified: dge-analysis/output/all-samples-analysis/res_aff_vs_unaff_significant_samples.csv
Modified: dge-analysis/output/all-samples-analysis/res_spta1_vs_unaff_df_genename_05.csv
Modified: dge-analysis/output/all-samples-analysis/res_spta1_vs_unaff_df_genename_padj05_lfc1.csv
Modified: dge-analysis/output/all-samples-analysis/res_spta1_vs_unaff_df_genename_padj1.csv
Modified: dge-analysis/output/all-samples-analysis/res_spta1_vs_unaff_df_genename_padj1_lfc1.csv
Modified: dge-analysis/output/all-samples-analysis/slc4a1_genes_of_interest.csv
Staged changes:
Modified: dge-analysis/analysis/_site.yml
Note that any generated files, e.g. HTML, png, CSS, etc., are not included in this status report because it is ok for generated content to have uncommitted changes.
These are the previous versions of the repository in which changes were
made to the R Markdown
(dge-analysis/analysis/subgroup-analysis.Rmd) and HTML
(docs/subgroup-analysis.html) files. If you’ve configured a
remote Git repository (see ?wflow_git_remote), click on the
hyperlinks in the table below to view the files as they were in that
past version.
| File | Version | Author | Date | Message |
|---|---|---|---|---|
| Rmd | 9f4f1fd | GitHub | 2025-11-06 | Reorganize repository. (#4) |
| html | 9f4f1fd | GitHub | 2025-11-06 | Reorganize repository. (#4) |
| html | a6247eb | GitHub | 2025-07-23 | Prepare for PhysGen submission. (#2) |
Ensure you have all necessary libraries installed and load the helper code.
library(tidyverse) # Available via CRAN
library(DESeq2) # Available via Bioconductor
library(RColorBrewer) # Available via CRAN
library(pheatmap) # Available via CRAN
library(genefilter) # Available via Bioconductor
library(limma) # Available via Bioconductor
library(gprofiler2) # Available via CRAN
library(biomaRt) # Available via Bioconductor
library(plotly) # Available via CRAN
library(ggpubr) # Available via CRAN
library(rmarkdown) # Available via CRAN
library(clusterProfiler) # Available via Bioconductor
library(org.Hs.eg.db) # Available via Bioconductor
library(ggrepel) # Available via CRAN
library(ReactomePA) # Available via Bioconductor
library(mygene) # Available via Bioconductor
library(DOSE) # Available via Bioconductor
library(enrichR) # Available via Bioconductor
library(STRINGdb) # Available via Bioconductor
library(EnhancedVolcano)
library(ComplexHeatmap)
We will be importing counts data from the star-salmon pipeline and our metadata for the project which is hosted on Box. This also ensures data is properly ordered by sample id.
# Set subgroup name from RMarkdown parameter
subgroup_name <- params$subgroup_name
subgroup_lower <- tolower(subgroup_name)
outpath_var <- paste0("subgroup-", subgroup_lower, "-analysis")
# Load metadata and counts
sample_metadata <- read_csv("data/Metadata_2024_11_20.csv")
row.names(sample_metadata) <- sample_metadata$ID
counts <- read_tsv("data/star-salmon/salmon_merged_gene_counts_length_scaled.tsv")
# Load genes of interest
genes_of_interest <- read_csv("data/Prioritized_Genes_From_WGS_2024_11_19.csv") %>%
pull(Genes) %>%
unique() %>%
na.omit()
genes_of_interest <- unique(c(genes_of_interest, "CHI3L1"))
# Process counts
counts <- data.frame(counts, row.names = 1, check.names = FALSE)
counts$Ensembl_ID <- row.names(counts)
drop <- c("Ensembl_ID", "gene_name")
gene_info <- counts[, drop]
counts <- counts[, !(names(counts) %in% drop)]
# Identify affected subgroup members
sample_metadata <- sample_metadata %>%
mutate(Subgroup_list = strsplit(Subgroup, ",")) %>%
mutate(in_subgroup = purrr::map_lgl(Subgroup_list, ~ subgroup_name %in% trimws(.))) %>%
mutate(group = dplyr::case_when(
in_subgroup ~ subgroup_name,
Subgroup == "Unaffected" ~ "Unaffected",
TRUE ~ NA_character_
)) %>%
filter(!is.na(group))
# Align metadata and counts
sample_metadata$ID <- as.character(sample_metadata$ID)
filtered_sample_ids <- sample_metadata$ID
counts <- counts[, colnames(counts) %in% filtered_sample_ids, drop = FALSE]
counts <- counts[, match(sample_metadata$ID, colnames(counts))]
# Safety check: ensure order match
stopifnot(all(colnames(counts) == sample_metadata$ID))
# Retrieve gene annotations
genes_biomart <- retrieve_gene_info(values = gene_info$Ensembl_ID,
filters = "ensembl_gene_id_version")
# Ensure relevant columns are factors
sample_metadata <- sample_metadata %>%
mutate(
Family = factor(Family),
Affected = factor(Affected),
Batch = factor(Batch),
Sex = factor(Sex),
Ancestry = factor(Ancestry),
Category = factor(Category),
group = factor(group) # key design variable: subgroup vs. Unaffected
)
# Create DESeqDataSet using group as the main condition
dds <- DESeqDataSetFromMatrix(
countData = round(counts),
colData = sample_metadata,
design = ~ Batch + group
)
# Pre-filtering: keep genes with sufficient total counts
keep <- rowSums(counts(dds)) >= 50
dds <- dds[keep, ]
# Run DESeq
dds <- DESeq(dds)
# Normalize counts
counts_norm <- counts(dds, normalized = TRUE)
Perform count data transformation by variance stabilizing transformation (vst) on normalized counts.
vsd <- vst(dds, blind = FALSE)
# Create output directory if it doesn't exist
dir.create(file.path("output", outpath_var), recursive = TRUE, showWarnings = FALSE)
# Extract VST-normalized counts
counts_vst <- assay(vsd)
write.csv(counts_vst, file.path("output", outpath_var, "counts_vst.csv"))
# Construct design matrix using group
mm <- model.matrix(~ Batch + group, colData(vsd))
# Remove batch effect
counts_vst_limma <- limma::removeBatchEffect(
counts_vst,
batch = vsd$Batch,
design = mm
)
Coefficients not estimable: batch1 batch2
# Save corrected matrix
write.csv(counts_vst_limma, file = file.path("output", outpath_var, "counts_vst_limma.csv"))
# Store back in DESeqTransform object
vsd_limma <- vsd
assay(vsd_limma) <- counts_vst_limma
# Compute sample distance matrix from VST + batch-corrected expression
sample_dists_all <- dist(t(assay(vsd_limma)))
sample_dist_matrix_all <- as.matrix(sample_dists_all)
# Label rows and columns using Batch and group
rownames(sample_dist_matrix_all) <- paste(vsd_limma$Batch, vsd_limma$group, sep = " | ")
colnames(sample_dist_matrix_all) <- paste(vsd_limma$ID, vsd_limma$group, sep = " | ")
# Define color palette
colors <- colorRampPalette(rev(brewer.pal(9, "Blues")))(255)
# Plot distance heatmap
pheatmap(sample_dist_matrix_all,
clustering_distance_rows = sample_dists_all,
clustering_distance_cols = sample_dists_all,
col = colors
)

Our below PCA shows that there does not seem to be a batch-related effect occurring after using limma. However, we can see that our 3 male samples are grouping. Given this knowledge, removing them from downstream analyses is the best option.
pca_data_all <- plotPCA(vsd_limma,
intgroup = c("Batch", "Variant"),
returnData = TRUE
)
percent_var_all <- round(100 * attr(pca_data_all, "percentVar"))
ggplot(pca_data_all, aes(PC1, PC2)) +
geom_point(aes(colour = Variant, shape = Batch), size = 4) +
xlab(paste0("PC1: ", percent_var_all[1], "% variance")) +
ylab(paste0("PC2: ", percent_var_all[2], "% variance")) +
coord_fixed()

# Run PCA on VST-transformed, batch-corrected data
pca_data_all <- plotPCA(vsd_limma,
intgroup = c("group"),
returnData = TRUE
)
percent_var_all <- round(100 * attr(pca_data_all, "percentVar"))
# Plot PCA with subgroup annotations
ggplot(pca_data_all, aes(PC1, PC2)) +
geom_point(aes(colour = group), size = 5) +
scale_colour_manual(
values = c(
"#1b9e77", "#d95f02", "#7570b3", "#e7298a", "#66a61e",
"#e6ab02", "#a6761d", "#666666"
),
name = "Group"
) +
geom_text_repel(aes(label = name), size = 3) +
xlab(paste0("PC1: ", percent_var_all[1], "% variance")) +
ylab(paste0("PC2: ", percent_var_all[2], "% variance")) +
ggthemes::theme_clean()

# Define custom annotation colors for heatmaps or pheatmap plots
study_group_colors <- c(
"ENE" = "#BFDFBF", # Light green
"IMM" = "#EEBFEE", # Light purple
"SOL" = "#FFFF33", # Yellow
"STR" = "#BFBFFF", # Light blue
"RBC" = "#FFD700", # Gold
"N/A" = "darkgray"
)
group_colors <- c(
"Potassium" = "#80B1D3",
"HPP" = "#FB8072",
"Ion_Channel" = "#FDB462",
"CHRN" = "#B3DE69",
"RBC" = "#BC80BD",
"Mito" = "#CCEBC5",
"Unaffected" = "gray40"
)
ann_colors <- list(
Batch = c(B1 = "purple", B2 = "firebrick", B3 = "goldenrod"),
Affected = c(Affected = "green4", Unaffected = "navy"),
Study_group = study_group_colors,
group = group_colors
)
# Perform differential expression analysis for selected subgroup vs Unaffected
res_subgroup_vs_unaff <- results(dds, contrast = c("group", subgroup_name, "Unaffected"))
# Define output file path
res_file_name <- file.path("output", outpath_var, paste0("res_", subgroup_lower, "_vs_unaff.csv"))
# Process and save results
res_subgroup_vs_unaff_df <- process_and_save_results(res_subgroup_vs_unaff, res_file_name)
# Sort by adjusted p-value
res_subgroup_vs_unaff_df <- arrange(res_subgroup_vs_unaff_df, padj)
# Filter: padj < 0.05
res_subgroup_vs_unaff_df_05 <- subset(res_subgroup_vs_unaff_df, padj < 0.05)
# Filter: padj < 0.1
res_subgroup_vs_unaff_df_1 <- subset(res_subgroup_vs_unaff_df, padj < 0.1)
# Further filter: padj < 0.1 & |log2FC| ≥ 1
res_subgroup_vs_unaff_df_padj1_lfc1 <- subset(
res_subgroup_vs_unaff_df_1,
abs(log2FoldChange) >= 1
)
# Further filter: padj < 0.05 & |log2FC| ≥ 1
res_subgroup_vs_unaff_df_padj05_lfc1 <- subset(
res_subgroup_vs_unaff_df_05,
abs(log2FoldChange) >= 1
)
# Print summary
summary(res_subgroup_vs_unaff)
out of 21035 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up) : 2, 0.0095%
LFC < 0 (down) : 0, 0%
outliers [1] : 92, 0.44%
low counts [2] : 0, 0%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# Ensure results are ordered by adjusted p-value
res_subgroup_vs_unaff_df <- res_subgroup_vs_unaff_df[order(res_subgroup_vs_unaff_df$padj), ]
# Get top significant genes with padj < 0.1 and |log2FC| ≥ 1
topgenes_byensemblid <- rownames(res_subgroup_vs_unaff_df_padj1_lfc1)
# Subset normalized matrix
topgenes_mat <- assay(vsd_limma)[topgenes_byensemblid, , drop = FALSE]
# Normalize expression by row (gene) mean
if (nrow(topgenes_mat) == 1) {
topgenes_mat <- topgenes_mat - mean(topgenes_mat)
} else {
topgenes_mat <- topgenes_mat - rowMeans(topgenes_mat)
}
# Map Ensembl IDs to gene symbols
ensembl_to_gene <- setNames(gene_info$gene_name, gene_info$Ensembl_ID)
rownames(topgenes_mat) <- ensembl_to_gene[rownames(topgenes_mat)]
# Re-order matrix by significance
topgenes_mat <- topgenes_mat[order(res_subgroup_vs_unaff_df$padj[topgenes_byensemblid]), , drop = FALSE]
# Prepare annotation dataframe
annotation_df <- colData(vsd_limma) %>%
as.data.frame() %>%
dplyr::select(group, Affected)
# Define output path using lowercase subgroup name
outpath_subgroup <- paste0("subgroup-", tolower(subgroup_name), "-analysis")
# Ensure the directory exists
if (!dir.exists(file.path("output", outpath_subgroup))) {
dir.create(file.path("output", outpath_subgroup), recursive = TRUE)
}
# Save heatmap to PNG
heatmap_file <- file.path("output", outpath_subgroup, paste0(subgroup_name, "_padj1_heatmap.png"))
png(heatmap_file, width = 14, height = 10, units = "in", res = 1200)
ComplexHeatmap::pheatmap(
topgenes_mat,
color = colorRampPalette(rev(brewer.pal(n = 9, name = "RdYlBu")))(50),
annotation_col = annotation_df,
annotation_colors = ann_colors,
fontsize = 7,
angle_col = c("0"),
cellheight = 10,
cellwidth = 24,
border_color = "black",
heatmap_legend_param = list(title = "")
)
dev.off()
quartz_off_screen
2
# Order results by adjusted p-value
res_subgroup_vs_unaff_df <- res_subgroup_vs_unaff_df[order(res_subgroup_vs_unaff_df$padj), ]
# Get top significant genes with |log2FoldChange| >= 1 and padj < 0.05
topgenes_byensemblid <- rownames(res_subgroup_vs_unaff_df_padj05_lfc1)
# Extract matrix subset
topgenes_subgroup_vs_unaff_05 <- assay(vsd_limma)[topgenes_byensemblid, , drop = FALSE]
# Normalize each row by subtracting its mean
if (nrow(topgenes_subgroup_vs_unaff_05) == 1) {
topgenes_subgroup_vs_unaff_05 <- topgenes_subgroup_vs_unaff_05 - mean(topgenes_subgroup_vs_unaff_05)
} else {
topgenes_subgroup_vs_unaff_05 <- topgenes_subgroup_vs_unaff_05 - rowMeans(topgenes_subgroup_vs_unaff_05)
}
# Map Ensembl IDs to gene names
ensembl_to_gene <- setNames(gene_info$gene_name, gene_info$Ensembl_ID)
current_ensembl_ids <- rownames(topgenes_subgroup_vs_unaff_05)
new_row_names <- ensembl_to_gene[current_ensembl_ids]
rownames(topgenes_subgroup_vs_unaff_05) <- new_row_names
# Order by significance
topgenes_subgroup_vs_unaff_05 <- topgenes_subgroup_vs_unaff_05[order(res_subgroup_vs_unaff_df$padj[topgenes_byensemblid]), , drop = FALSE]
# Prepare sample annotation
df <- colData(vsd_limma) %>%
as.data.frame() %>%
dplyr::select(group)
# Define output path using lowercase subgroup name
outpath_subgroup <- paste0("subgroup-", tolower(subgroup_name), "-analysis")
# Ensure the directory exists
if (!dir.exists(file.path("output", outpath_subgroup))) {
dir.create(file.path("output", outpath_subgroup), recursive = TRUE)
}
# Define file name
heatmap_file <- file.path("output", outpath_subgroup, paste0(subgroup_name, "_significant_padj05_heatmap.png"))
# Save heatmap to PNG
png(heatmap_file, width = 10, height = 8, units = "in", res = 300)
ComplexHeatmap::pheatmap(
topgenes_subgroup_vs_unaff_05,
color = colorRampPalette(rev(brewer.pal(n = 9, name = "RdYlBu")))(50),
annotation_col = df,
annotation_colors = ann_colors,
fontsize = 7,
angle_col = c("0"),
cellheight = 10,
cellwidth = 24,
border_color = "black",
heatmap_legend_param = list(title = "")
)
dev.off()
quartz_off_screen
2
# Extract relevant columns from genes_biomart (first and last columns)
gb_df <- genes_biomart[, c(1, ncol(genes_biomart))]
# Copy results dataframe to add gene annotations
res_subgroup_vs_unaff_df_genename <- res_subgroup_vs_unaff_df
# Add Ensembl IDs as a new column
res_subgroup_vs_unaff_df_genename$Ensembl_ID <- row.names(res_subgroup_vs_unaff_df)
# Merge gene annotation information from gene_info using Ensembl IDs
res_subgroup_vs_unaff_df_genename <- merge(
x = res_subgroup_vs_unaff_df_genename,
y = gene_info,
by = "Ensembl_ID",
all.x = TRUE
)
# Reorder columns to place gene_name and Ensembl_ID at the front
res_subgroup_vs_unaff_df_genename <- res_subgroup_vs_unaff_df_genename[
,
c("gene_name", "Ensembl_ID", setdiff(names(res_subgroup_vs_unaff_df_genename), c("gene_name", "Ensembl_ID")))
]
# Sort the dataframe by adjusted p-value (padj)
res_subgroup_vs_unaff_df_genename <- res_subgroup_vs_unaff_df_genename[
order(res_subgroup_vs_unaff_df_genename$padj),
]
# Define output file path for the annotated results
res_file_genename <- file.path(
"output", outpath_var,
"res_subgroup_vs_unaff_df_genename.csv"
)
# Save the annotated results to a CSV file
write.csv(res_subgroup_vs_unaff_df_genename, file = res_file_genename, row.names = FALSE)
# Parameters for the function
res_data <- res_subgroup_vs_unaff_df_genename
gene_labels <- "gene_name"
x_col <- "log2FoldChange"
y_col <- "padj"
select_genes <- ""
xlab_text <- bquote(~ Log[2] ~ "fold change")
ylab_text <- bquote(~ -Log[10] ~ "padj")
xlim_range <- c(-25, 25)
ylim_range <- c(0, 7)
output_volcano_file <- file.path("output", outpath_var, paste0("volcano-plot-", tolower(subgroup_name), ".png"))
# Generate and save the volcano plot
generate_volcano_plot(
res_data = res_data, gene_labels = gene_labels, x_col = x_col,
y_col = y_col, select_genes = select_genes, xlab_text = xlab_text,
ylab_text = ylab_text, p_cutoff = 0.05, fc_cutoff = 1.0,
xlim_range = xlim_range, ylim_range = ylim_range,
output_file = output_volcano_file
)

# Process and save the data
process_and_save_filtered_results(res_subgroup_vs_unaff_df_genename,
padj_threshold = 0.05, lfc_threshold = NULL,
outpath = outpath_var,
filename = paste0("res_", subgroup_lower, "_vs_unaff_df_genename_05.csv")
)
process_and_save_filtered_results(res_subgroup_vs_unaff_df_genename,
padj_threshold = 0.05, lfc_threshold = 1,
outpath = outpath_var,
filename = paste0("res_", subgroup_lower, "_vs_unaff_df_genename_padj05_lfc1.csv")
)
process_and_save_filtered_results(res_subgroup_vs_unaff_df_genename,
padj_threshold = 0.1, lfc_threshold = NULL,
outpath = outpath_var,
filename = paste0("res_", subgroup_lower, "_vs_unaff_df_genename_padj1.csv")
)
process_and_save_filtered_results(res_subgroup_vs_unaff_df_genename,
padj_threshold = 0.1, lfc_threshold = 1,
outpath = outpath_var,
filename = paste0("res_", subgroup_lower, "_vs_unaff_df_genename_padj1_lfc1.csv")
)
# Filter gene names that are not Ensembl IDs
filtered_gene_names <- res_subgroup_vs_unaff_df_genename$gene_name[!grepl("^ENS", res_subgroup_vs_unaff_df_genename$gene_name)]
# Generate MA plot
maplot <- generate_ma_plot(
data = res_subgroup_vs_unaff_df,
genenames = as.vector(res_subgroup_vs_unaff_df_genename$gene_name),
main_title = paste0(subgroup_name, " vs Unaffected MA Plot"),
top_genes = 30
)
maplot

# Extract significant genes from the MA plot
significant_data <- maplot$data %>%
filter(grepl("Up|Down", sig)) %>%
mutate(direction = ifelse(grepl("Up", sig), "Up", "Down")) %>%
dplyr::select(-sig)
# Display a paged table of significant genes
paged_table(as.data.frame(significant_data), options = list(rows.print = 30))
# Save significant genes to CSV
output_maplot_siggenes <- file.path(
"output", outpath_var,
paste0("res_", subgroup_lower, "_vs_unaff_siggenes.csv")
)
write.csv(significant_data, file = output_maplot_siggenes, row.names = FALSE)
# Initialize STRINGdb
string_db <- STRINGdb$new(
version = "11.5",
species = 9606,
score_threshold = 100,
network_type = "full",
input_directory = ""
)
# Map significant genes to STRING IDs
mapped_degs <- string_db$map(significant_data, "name", removeUnmappedRows = TRUE)
Warning: we couldn't map to STRING 100% of your identifiers
if (nrow(mapped_degs) > 0) {
# Limit to top 29 STRING IDs
hits <- head(mapped_degs$STRING_id, 29)
# Add logFC-based coloring
mapped_degs_dec <- string_db$add_diff_exp_color(mapped_degs, logFcColStr = "lfc")
# Generate payload and plot network
payload_id <- string_db$post_payload(mapped_degs_dec$STRING_id, colors = mapped_degs_dec$color)
string_db$plot_network(hits, payload_id = payload_id)
} else {
message("No STRING IDs mapped — skipping STRING network plot.")
}
outpath_subgroup <- paste0("subgroup-", tolower(subgroup_name), "-analysis")
save.image(file = file.path("output", outpath_subgroup, paste0(subgroup_name, "-subgroup-analysis.RData")))
sessionInfo()
R version 4.5.1 (2025-06-13)
Platform: x86_64-apple-darwin20
Running under: macOS Sequoia 15.6.1
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/4.5-x86_64/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.5-x86_64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
time zone: America/Chicago
tzcode source: internal
attached base packages:
[1] grid stats4 stats graphics grDevices datasets utils
[8] methods base
other attached packages:
[1] ComplexHeatmap_2.24.1 EnhancedVolcano_1.26.0
[3] STRINGdb_2.20.0 enrichR_3.4
[5] DOSE_4.2.0 mygene_1.44.0
[7] txdbmaker_1.4.2 GenomicFeatures_1.60.0
[9] ReactomePA_1.52.0 ggrepel_0.9.6
[11] org.Hs.eg.db_3.21.0 AnnotationDbi_1.70.0
[13] clusterProfiler_4.16.0 rmarkdown_2.29
[15] ggpubr_0.6.1 plotly_4.11.0
[17] biomaRt_2.64.0 gprofiler2_0.2.3
[19] limma_3.64.1 genefilter_1.90.0
[21] pheatmap_1.0.13 RColorBrewer_1.1-3
[23] DESeq2_1.48.1 SummarizedExperiment_1.38.1
[25] Biobase_2.68.0 MatrixGenerics_1.20.0
[27] matrixStats_1.5.0 GenomicRanges_1.60.0
[29] GenomeInfoDb_1.44.0 IRanges_2.42.0
[31] S4Vectors_0.46.0 BiocGenerics_0.54.0
[33] generics_0.1.4 lubridate_1.9.4
[35] forcats_1.0.0 stringr_1.5.1
[37] dplyr_1.1.4 purrr_1.1.0
[39] readr_2.1.5 tidyr_1.3.1
[41] tibble_3.3.0 ggplot2_3.5.2
[43] tidyverse_2.0.0 workflowr_1.7.1
loaded via a namespace (and not attached):
[1] fs_1.6.6 bitops_1.0-9 enrichplot_1.28.4
[4] doParallel_1.0.17 httr_1.4.7 tools_4.5.1
[7] backports_1.5.0 R6_2.6.1 lazyeval_0.2.2
[10] GetoptLong_1.0.5 withr_3.0.2 graphite_1.54.0
[13] prettyunits_1.2.0 gridExtra_2.3 textshaping_1.0.1
[16] cli_3.6.5 labeling_0.4.3 sass_0.4.10
[19] systemfonts_1.2.3 Rsamtools_2.24.0 yulab.utils_0.2.0
[22] gson_0.1.0 foreign_0.8-90 R.utils_2.13.0
[25] WriteXLS_6.8.0 plotrix_3.8-4 rstudioapi_0.17.1
[28] RSQLite_2.4.2 shape_1.4.6.1 gridGraphics_0.5-1
[31] BiocIO_1.18.0 vroom_1.6.5 gtools_3.9.5
[34] car_3.1-3 GO.db_3.21.0 Matrix_1.7-3
[37] abind_1.4-8 R.methodsS3_1.8.2 lifecycle_1.0.4
[40] whisker_0.4.1 yaml_2.3.10 carData_3.0-5
[43] gplots_3.2.0 qvalue_2.40.0 SparseArray_1.8.0
[46] BiocFileCache_2.16.0 blob_1.2.4 promises_1.3.3
[49] crayon_1.5.3 ggtangle_0.0.7 lattice_0.22-7
[52] cowplot_1.2.0 annotate_1.86.1 KEGGREST_1.48.1
[55] pillar_1.11.0 knitr_1.50 fgsea_1.34.2
[58] rjson_0.2.23 codetools_0.2-20 fastmatch_1.1-6
[61] glue_1.8.0 getPass_0.2-4 ggfun_0.2.0
[64] data.table_1.17.8 vctrs_0.6.5 png_0.1-8
[67] treeio_1.32.0 gtable_0.3.6 gsubfn_0.7
[70] cachem_1.1.0 xfun_0.52 S4Arrays_1.8.1
[73] tidygraph_1.3.1 survival_3.8-3 iterators_1.0.14
[76] statmod_1.5.0 nlme_3.1-168 ggtree_3.16.3
[79] bit64_4.6.0-1 progress_1.2.3 filelock_1.0.3
[82] rprojroot_2.1.0 bslib_0.9.0 KernSmooth_2.23-26
[85] rpart_4.1.24 colorspace_2.1-1 DBI_1.2.3
[88] Hmisc_5.2-3 nnet_7.3-20 tidyselect_1.2.1
[91] processx_3.8.6 chron_2.3-62 bit_4.6.0
[94] compiler_4.5.1 curl_6.4.0 git2r_0.36.2
[97] httr2_1.2.0 graph_1.86.0 htmlTable_2.4.3
[100] xml2_1.3.8 DelayedArray_0.34.1 rtracklayer_1.68.0
[103] caTools_1.18.3 checkmate_2.3.2 scales_1.4.0
[106] callr_3.7.6 rappdirs_0.3.3 digest_0.6.37
[109] XVector_0.48.0 htmltools_0.5.8.1 pkgconfig_2.0.3
[112] base64enc_0.1-3 dbplyr_2.5.0 fastmap_1.2.0
[115] ggthemes_5.1.0 GlobalOptions_0.1.2 rlang_1.1.6
[118] htmlwidgets_1.6.4 UCSC.utils_1.4.0 farver_2.1.2
[121] jquerylib_0.1.4 jsonlite_2.0.0 BiocParallel_1.42.1
[124] GOSemSim_2.34.0 R.oo_1.27.1 RCurl_1.98-1.17
[127] magrittr_2.0.3 Formula_1.2-5 GenomeInfoDbData_1.2.14
[130] ggplotify_0.1.2 patchwork_1.3.1 Rcpp_1.1.0
[133] proto_1.0.0 ape_5.8-1 viridis_0.6.5
[136] sqldf_0.4-11 stringi_1.8.7 ggraph_2.2.1
[139] MASS_7.3-65 plyr_1.8.9 parallel_4.5.1
[142] Biostrings_2.76.0 graphlayouts_1.2.2 splines_4.5.1
[145] hash_2.2.6.3 circlize_0.4.16 hms_1.1.3
[148] locfit_1.5-9.12 ps_1.9.1 igraph_2.1.4
[151] ggsignif_0.6.4 reshape2_1.4.4 XML_3.99-0.18
[154] evaluate_1.0.4 renv_1.1.4 BiocManager_1.30.26
[157] foreach_1.5.2 tzdb_0.5.0 tweenr_2.0.3
[160] httpuv_1.6.16 polyclip_1.10-7 clue_0.3-66
[163] ggforce_0.5.0 broom_1.0.8 xtable_1.8-4
[166] restfulr_0.0.16 reactome.db_1.92.0 tidytree_0.4.6
[169] rstatix_0.7.2 later_1.4.2 ragg_1.4.0
[172] viridisLite_0.4.2 aplot_0.2.8 memoise_2.0.1
[175] GenomicAlignments_1.44.0 cluster_2.1.8.1 timechange_0.3.0