Skip to content

Commit 67b3eb3

Browse files
committed
v1.2.4 - linear regression added
1 parent 6c28fbd commit 67b3eb3

File tree

6 files changed

+155
-2
lines changed

6 files changed

+155
-2
lines changed

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ RUN R -e "\
7272
library(clusterProfiler); \
7373
library(org.Hs.eg.db); \
7474
library(enrichplot); \
75+
library(broom); \
76+
library(purrr); \
7577
sessionInfo(); \
7678
installed.packages()"
7779

app/app.R

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ library(lme4)
1010
library(lmerTest)
1111
library(shinyjs)
1212
library(DT)
13+
library(broom)
14+
library(purrr)
15+
1316

1417
# Source utility functions
1518
source("utilities.R")
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
linear_regression_server <- function(input, output, session, merged_data) {
2+
3+
regression_results_rv <- reactiveVal(NULL)
4+
5+
# Generate covariate inputs dynamically
6+
output$covariate_inputs <- renderUI({
7+
req(input$num_covariates)
8+
num <- input$num_covariates
9+
10+
lapply(seq_len(num), function(i) {
11+
tagList(
12+
selectInput(paste0("covariate", i), paste("Select Covariate", i),
13+
choices = colnames(merged_data()), selected = NULL),
14+
radioButtons(paste0("cov_type", i), paste("Covariate", i, "Type"),
15+
choices = c("Character", "Factor", "Numeric"), inline = TRUE)
16+
)
17+
})
18+
})
19+
20+
# Update dependent variable choices based on merged_data
21+
output$dependent_var_ui <- renderUI({
22+
req(merged_data())
23+
numeric_cols <- names(merged_data())[sapply(merged_data(), is.numeric)]
24+
selectInput("dependent_var", "Select Dependent Variable", choices = numeric_cols)
25+
})
26+
27+
28+
observe({
29+
req(merged_data())
30+
cols <- colnames(merged_data())
31+
32+
num_covs <- as.numeric(input$num_covariates %||% 0)
33+
for (i in seq_len(num_covs)) {
34+
updateSelectInput(session, paste0("covariate", i), choices = c("None", cols))
35+
}
36+
})
37+
38+
39+
40+
# Perform linear regression on NPX variables
41+
observeEvent(input$run_regression, {
42+
req(merged_data())
43+
df <- merged_data()
44+
45+
# Identify numeric variables (potential biomarkers)
46+
excluded_cols <- c(input$dependent_var, unlist(lapply(seq_len(input$num_covariates), function(i) input[[paste0("covariate", i)]])))
47+
npx_vars <- colnames(df)[sapply(df, is.numeric) & !(colnames(df) %in% excluded_cols)]
48+
49+
50+
# Standardize NPX if Z-score selected
51+
if (input$npx_or_zscore == "Z-score") {
52+
df <- df %>%
53+
mutate(across(all_of(npx_vars), ~ scale(.), .names = "{.col}_z"))
54+
npx_vars <- paste0(npx_vars, "_z")
55+
}
56+
57+
# Collect user input
58+
dep_var <- input$dependent_var
59+
covariates <- unlist(lapply(seq_len(input$num_covariates), function(i) input[[paste0("covariate", i)]]))
60+
covariates <- covariates[!is.na(covariates) & covariates != ""]
61+
62+
# Preprocess covariate types
63+
for (i in seq_along(covariates)) {
64+
cov <- covariates[i]
65+
cov_type <- input[[paste0("cov_type", i)]]
66+
if (!is.null(cov_type)) {
67+
df[[cov]] <- switch(cov_type,
68+
"Character" = as.character(df[[cov]]),
69+
"Factor" = as.factor(df[[cov]]),
70+
"Numeric" = as.numeric(df[[cov]]))
71+
}
72+
}
73+
74+
# Run linear regression
75+
results <- purrr::map_dfr(npx_vars, function(var) {
76+
form <- as.formula(
77+
paste(dep_var, "~", paste(c(var, covariates), collapse = " + "))
78+
)
79+
model <- tryCatch(lm(form, data = df), error = function(e) NULL)
80+
if (is.null(model)) return(NULL)
81+
82+
broom::tidy(model) %>%
83+
filter(term == var) %>%
84+
mutate(biomarker = gsub("_z$", "", var))
85+
})
86+
87+
# Format and adjust
88+
if (nrow(results) > 0) {
89+
results_clean <- results %>%
90+
mutate(adj.p.value = p.adjust(p.value, method = "BH")) %>%
91+
select(biomarker, estimate, std.error, p.value, adj.p.value) %>%
92+
arrange(adj.p.value)
93+
94+
regression_results_rv(results_clean)
95+
96+
output$regression_results <- DT::renderDataTable({
97+
DT::datatable(results_clean, options = list(pageLength = 15), rownames = FALSE)
98+
})
99+
} else {
100+
output$regression_results <- DT::renderDataTable({
101+
DT::datatable(data.frame(Message = "No valid models or no significant results."), rownames = FALSE)
102+
})
103+
}
104+
})
105+
106+
output$download_regression <- downloadHandler(
107+
filename = function() {
108+
paste0("linear_regression_results_", Sys.Date(), ".csv")
109+
},
110+
content = function(file) {
111+
results <- regression_results_rv()
112+
if (!is.null(results)) {
113+
readr::write_csv(results, file)
114+
}
115+
}
116+
)
117+
118+
}

app/server/server_main.R

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ source(file.path("server", "server_lme_plot.R"))
2626
source(file.path("server", "server_pathway_heatmap.R"))
2727
source(file.path("server", "server_qc_plot.R"))
2828
#source("server/server_plate_randomization.R")
29+
source(file.path("server", "server_linear_regression.R"))
2930

3031
print("All server modules sourced")
3132
print("server_lme.R sourced successfully")
@@ -68,4 +69,6 @@ server_main <- function(input, output, session, merged_data, var_key_merged, tte
6869
safe_call(lme_plot_server, input, output, session, merged_data)
6970
safe_call(pathway_heatmap_server, input, output, session, shared_enrichment_results, ttest_results)
7071
safe_call(qc_plot_server, input, output, session, merged_data)
72+
safe_call(linear_regression_server, input, output, session, merged_data)
73+
7174
}

app/ui/ui_linear_regression.R

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
linear_regression_ui <- function() {
2+
tagList(
3+
h3("Linear Regression Analysis"),
4+
5+
radioButtons("npx_or_zscore", "NPX value type:",
6+
choices = c("Raw NPX", "Z-score"), selected = "Raw NPX", inline = TRUE),
7+
8+
# selectInput("dependent_var", "Select Dependent Variable",
9+
# choices = NULL, selected = NULL),
10+
uiOutput("dependent_var_ui"),
11+
12+
13+
numericInput("num_covariates", "Number of Covariates", value = 0, min = 0, max = 5),
14+
15+
uiOutput("covariate_inputs"),
16+
17+
actionButton("run_regression", "Run Linear Regression"),
18+
19+
hr(),
20+
DT::dataTableOutput("regression_results"),
21+
downloadButton("download_regression", "Download Results", class = "btn-success")
22+
)
23+
}

app/ui/ui_main.R

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ source("ui/ui_lme_plot.R")
3131
source("ui/ui_pathway_heatmap.R")
3232
source("ui/ui_qc_plot.R")
3333
#source("ui/ui_plate_randomization.R")
34+
source("ui/ui_linear_regression.R")
35+
3436

3537
single_ui <- function() {
3638
page_sidebar(
@@ -135,7 +137,9 @@ single_ui <- function() {
135137
nav_panel("8. Violin Plot", violin_plot_ui())
136138
)
137139
),
138-
nav_panel("F. Pathway Enrichment Analysis", pathway_enrichment_ui())
140+
nav_panel("F. Pathway Enrichment Analysis", pathway_enrichment_ui()
141+
),
142+
nav_panel("G. Linear Regression", linear_regression_ui())
139143
),
140144

141145
tags$footer(
@@ -152,7 +156,7 @@ single_ui <- function() {
152156
),
153157
div(
154158
class = "footer-section footer-right",
155-
"Version 1.2.3"
159+
"Version 1.2.4"
156160
)
157161
)
158162
)

0 commit comments

Comments
 (0)