diff --git a/.gitignore b/.gitignore index b71e700..b191ef8 100644 --- a/.gitignore +++ b/.gitignore @@ -34,9 +34,4 @@ vignettes/*.RData inst/shiny/rsconnect # inst/shiny/www/.. -inst/shiny/www/report_full.Rmd -inst/shiny/www/report_full.html -inst/shiny/www/report_full_purl.R -inst/shiny/www/report_meta.Rmd -inst/shiny/www/report_meta.html -inst/shiny/www/report_meta_purl.R +inst/shiny/www/report_expanded* diff --git a/inst/shiny/global.R b/inst/shiny/global.R index 775832e..a5fdda3 100644 --- a/inst/shiny/global.R +++ b/inst/shiny/global.R @@ -1,46 +1,10 @@ -# Function for overwriting the param key of the report YAML -overwrite_params <- function(file, params) { - # Load file into memory - .r <- readLines(file) - params_lines_start <- which(.r == "#' params:") # Assumes a line on its own - params_lines_end <- max(which(.r == "#' ---")) # Assumes 'params:' block is the last element - - #Create YAML - tmpfile <- tempfile() # Temp file to hold dput output - params_yaml <- character() - - for (i in seq_along(params)) { - dput(params[[i]], tmpfile) - params_yaml <- - c(params_yaml, - sprintf("#' %s: !r %s", names(params)[i], - paste0(readLines(tmpfile), collapse = ""))) - } - - # Insert into character vector - new_file <- c(.r[seq_len(params_lines_start - 1)], - params_yaml, - .r[params_lines_end:length(.r)]) - - writeLines(text = new_file, con = file) +# Function for dput'ting objects into a character string +cput <- function(x) { + f <- tempfile() + dput(x, file = f) + return(readLines(f)) } -# Testing function -# params <- list(file = "../../../data/freshVsFrozen.csv", -# header = TRUE, sep = ";", -# quote = "\"", -# model_cols = c("PreVsPost.Fresh.pval", "PreVsPost.Frozen.pval"), -# meta_large_vals = FALSE, -# init_par = c(pie1 = 0.7, mu = 1, sigma = 1, rho = 0.5), -# meta_method = "NM", -# meta_max_ite = 50L, -# meta_positive_rho = TRUE, -# meta_IDR_thres_type = "IDR", -# meta_IDR_thres = 0.05, -# theta = GMCM::rtheta()) -# overwrite_params(file = "inst/shiny/www/CopyOfreport_meta.R", params) - - # Function for plotting meta results meta_plot <- function(fit, # A fitted object data idr, # Output from get.IDR diff --git a/inst/shiny/run-reports.R b/inst/shiny/run-reports.R index 2f641dd..c17fa72 100644 --- a/inst/shiny/run-reports.R +++ b/inst/shiny/run-reports.R @@ -2,14 +2,19 @@ library("knitr") library("rmarkdown") library("GMCM") -# GENERAL GMCM ---- -report_path <- "inst/shiny/www/report_full.Rmd" +# dput object to character string +cput <- function(x) { + f <- tempfile() + dput(x, file = f) + return(readLines(f)) +} + # SPECIAL GMCM ---- report_path <- "inst/shiny/www/report_meta.Rmd" # Parameters to expand -params <- list(input_file = "../../../data/u133VsExon.csv", +params <- list(data_file = "../../../data/u133VsExon.csv", header = TRUE, sep = ";", quote = '\"', @@ -22,13 +27,6 @@ params <- list(input_file = "../../../data/u133VsExon.csv", meta_IDR_thres_type = "IDR", meta_IDR_thres = 1e-04) -# dput object to character string -cput <- function(x) { - f <- tempfile() - dput(x, file = f) - return(readLines(f)) -} - expand_args <- c(list(file = report_path), params) report_expanded <- do.call(knitr::knit_expand, expand_args) @@ -36,6 +34,10 @@ report_expanded_path <- gsub("/report_", "/report_expanded_", report_path) cat(report_expanded, file = report_expanded_path) +# We can also purl +knitr::purl(report_expanded_path, output = gsub(".Rmd$", ".R", report_expanded_path), + documentation = 0) + # Render the expanded document rmarkdown::render( input = report_expanded_path, @@ -44,8 +46,40 @@ rmarkdown::render( envir = new.env(parent = globalenv()) ) -# We can also purl + + + +# GENERAL GMCM ---- +report_path <- "inst/shiny/www/report_full.Rmd" + +# Parameters to expand +params <- list(data_file = "../../../data/u133VsExon.csv", + header = TRUE, + sep = ";", + quote = '\"', + model_cols = c("u133", "exon"), + theta = GMCM::rtheta(m = 2, d = 2), + fit_method = "NM", + max_ite = 50, + full_class_type = "thres_prob", + full_thres_prob = 0.9) + +expand_args <- c(list(file = report_path), params) +report_expanded <- do.call(knitr::knit_expand, expand_args) +report_expanded_path <- gsub("/report_", "/report_expanded_", report_path) + +cat(report_expanded, file = report_expanded_path) + +# We can purl knitr::purl(report_expanded_path, output = gsub(".Rmd$", ".R", report_expanded_path), documentation = 0) +# Render the expanded document +rmarkdown::render( + input = report_expanded_path, + output_options = list(self_contained = TRUE), + params = params, + envir = new.env(parent = globalenv()) +) + diff --git a/inst/shiny/server.R b/inst/shiny/server.R index 5c629cd..df015b9 100644 --- a/inst/shiny/server.R +++ b/inst/shiny/server.R @@ -966,57 +966,73 @@ shinyServer(function(input, output, session) { # Output reports -------- # https://shiny.rstudio.com/articles/generating-reports.html + full_expand_rmd <- reactive({ + # Copy the report file to a temporary directory before processing it, in + # case we don't have write permissions to the current working dir (which + # can happen when deployed). + temp_file <- file.path(tempdir(), "report_full.Rmd") + file.copy("www/report_full.Rmd", temp_file, overwrite = TRUE) + message("Copied 'www/report_full.Rmd' into ", temp_file) + + + # Set up parameters to pass to Rmd document + params <- list(data_file = input$in_file$datapath, + header = input$header, + sep = input$sep, + quote = input$quote, + model_cols = input$model_cols, + theta = as.theta(full_start_theta()), + fit_method = input$full_method, + max_ite = input$full_max_ite, + full_class_type = input$full_class_type, + full_thres_prob = input$full_thres_prob) + + # Expand the args in params + knit_expand_args <- c(list(file = temp_file), params) + report_expanded <- do.call(knitr::knit_expand, knit_expand_args) + message(temp_file, " expanded with parameters.") + + # Write the R file and path to it + temp_file_out <- gsub("report_", "report_expanded_", temp_file) + cat(report_expanded, file = temp_file_out) + message("Expanded .Rmd written to ", temp_file_out) + + return(temp_file_out) + + }) + output$full_dl_r <- downloadHandler( filename = "report_full.R", content = function(file) { - file.copy("www/report_full.R", file, overwrite = TRUE) + expanded_rmd <- full_expand_rmd() + outfile <- gsub(".Rmd$", ".R", expanded_rmd) + message("purl ", expanded_rmd, " to ", outfile) + knitr::purl(expanded_rmd, + output = outfile, + documentation = 0) + + file.copy(outfile, file, overwrite = TRUE) } ) output$full_dl_rmd <- downloadHandler( filename = "report_full.Rmd", content = function(file) { - temp_file <- file.path(tempdir(), "report_full.R") - file.copy("www/report_full.R", temp_file, overwrite = TRUE) - out <- spin(hair = temp_file, - knit = FALSE, - format = "Rmd") - writeLines(text = readLines(out), con = file) + file.copy(full_expand_rmd(), file, overwrite = TRUE) } ) output$full_dl_html <- downloadHandler( filename = "report_full.html", content = function(file) { - # Copy the report file to a temporary directory before processing it, in - # case we don't have write permissions to the current working dir (which - # can happen when deployed). - temp_file <- file.path(tempdir(), "report_full.R") - file.copy("www/report_full.R", temp_file, overwrite = TRUE) - - # Set up parameters to pass to Rmd document - params <- list(file = input$in_file$datapath, - header = input$header, - sep = input$sep, - quote = input$quote, - model_cols = input$model_cols, - theta = as.theta(full_start_theta()), - fit_method = input$full_method, - max_ite = input$full_max_ite, - full_class_type = input$full_class_type, - full_thres_prob = input$full_thres_prob) - print(str(params)) - - # Spin and knit the document, passing in the `params` list, and eval it in a - # child of the global environment (this isolates the code in the document - # from the code in this app). + # Render the expanded Rmd document rmarkdown::render( - input = temp_file, + input = full_expand_rmd(), output_file = file, output_options = list(self_contained = TRUE), - params = params, envir = new.env(parent = globalenv()) ) + message("Expanded .Rmd rendered.") } ) @@ -1024,10 +1040,6 @@ shinyServer(function(input, output, session) { - - - - # __SPECIAL GMCM ________________________________________________________ ---- # Initalise reactive values ---- @@ -1292,61 +1304,78 @@ shinyServer(function(input, output, session) { # Output reports -------- # https://shiny.rstudio.com/articles/generating-reports.html + + meta_expand_rmd <- reactive({ + # Copy the report file to a temporary directory before processing it, in + # case we don't have write permissions to the current working dir (which + # can happen when deployed). + + temp_file <- file.path(tempdir(), "report_meta.Rmd") + file.copy("www/report_meta.Rmd", temp_file, overwrite = TRUE) + message("Copied 'www/report_meta.Rmd' into ", temp_file) + + # Set up parameters to pass to Rmd document + params <- list(data_file = input$in_file$datapath, + header = input$header, + sep = input$sep, + quote = input$quote, + model_cols = input$model_cols, + meta_large_vals = input$meta_large_vals, + init_par = c(pie1 = input$par1, + mu = input$par2, + sigma = input$par3, + rho = input$par4), + meta_method = input$meta_method, + meta_max_ite = input$meta_max_ite, + meta_positive_rho = input$meta_positive_rho, + meta_IDR_thres_type = input$meta_IDR_thres_type, + meta_IDR_thres = input$meta_IDR_thres) + + # Expand the args in params + knit_expand_args <- c(list(file = temp_file), params) + report_expanded <- do.call(knitr::knit_expand, knit_expand_args) + message(temp_file, " expanded with parameters.") + + # Write the R file and path to it + temp_file_out <- gsub("report_", "report_expanded_", temp_file) + cat(report_expanded, file = temp_file_out) + message("Expanded .Rmd written to ", temp_file_out) + + return(temp_file_out) + }) + output$meta_dl_r <- downloadHandler( filename = "report_meta.R", content = function(file) { - file.copy("www/report_meta.R", file, overwrite = TRUE) + expanded_rmd <- meta_expand_rmd() + outfile <- gsub(".Rmd$", ".R", expanded_rmd) + message("purl ", expanded_rmd, " to ", outfile) + knitr::purl(expanded_rmd, + output = outfile, + documentation = 0) + + file.copy(outfile, file, overwrite = TRUE) } ) output$meta_dl_rmd <- downloadHandler( filename = "report_meta.Rmd", content = function(file) { - temp_file <- file.path(tempdir(), "report_meta.R") - file.copy("www/report_meta.R", temp_file, overwrite = TRUE) - out <- spin(hair = temp_file, - knit = FALSE, - format = "Rmd") - writeLines(text = readLines(out), con = file) + file.copy(meta_expand_rmd(), file, overwrite = TRUE) } ) output$meta_dl_html <- downloadHandler( filename = "report_meta.html", content = function(file) { - # Copy the report file to a temporary directory before processing it, in - # case we don't have write permissions to the current working dir (which - # can happen when deployed). - temp_file <- file.path(tempdir(), "report_meta.R") - file.copy("www/report_meta.R", temp_file, overwrite = TRUE) - - # Set up parameters to pass to Rmd document - params <- list(file = input$in_file$datapath, - header = input$header, - sep = input$sep, - quote = input$quote, - model_cols = input$model_cols, - meta_large_vals = input$meta_large_vals, - init_par = c(pie1 = input$par1, - mu = input$par2, - sigma = input$par3, - rho = input$par4), - meta_method = input$meta_method, - meta_max_ite = input$meta_max_ite, - meta_positive_rho = input$meta_positive_rho, - meta_IDR_thres_type = input$meta_IDR_thres_type, - meta_IDR_thres = input$meta_IDR_thres) - - # Spin and knit the document, passing in the `params` list, and eval it in a - # child of the global environment (this isolates the code in the document - # from the code in this app). + # Render the expanded Rmd document rmarkdown::render( - input = temp_file, + input = meta_expand_rmd(), output_file = file, output_options = list(self_contained = TRUE), - params = params, envir = new.env(parent = globalenv()) ) + message("Expanded .Rmd rendered.") } ) diff --git a/inst/shiny/www/report_full.R b/inst/shiny/www/report_full.R deleted file mode 100644 index a099f19..0000000 --- a/inst/shiny/www/report_full.R +++ /dev/null @@ -1,128 +0,0 @@ -#' --- -#' title: "Unsupervised clustering with general GMCMs" -#' output: html_document -#' date: '`r Sys.time()`' -#' author: "Generated by the GMCM shiny app" -#' params: -#' file: !r file.path(getwd(), "../../../data/freshVsFrozen.csv") -#' header: TRUE -#' sep: ";" -#' quote: '"' -#' model_cols: !r c("PreVsPost.Fresh.pval", "PreVsPost.Frozen.pval") -#' theta: !r GMCM::rtheta(m = 2, d = 2) -#' fit_method: "NM" -#' max_ite: 50 -#' full_class_type: "thres_prob" -#' full_thres_prob: 0.9 -#' --- - - -# ---- knit-int, echo=FALSE, include=FALSE -set.seed(7869670) - -#' -#' ## Initalisation -#' The **GMCM**^[1][1]^ package is loaded. -# ---- load-packages, include=TRUE - -#install.packages("GMCM") # Uncomment to install the GMCM package -library("GMCM") - -#' -#' If **GMCM** is *not* installed, please uncomment the above line and rerun the script. -#' -#' ## Load data -#' The data is loaded and the first rows are printed -# ---- load-data, include=TRUE, echo=TRUE -ds <- read.table(file = params$file, - header = params$header, - sep = params$sep, - quote = params$quote) -head(ds, n = 4) - -#' -#' Next, the data is subset to the columns of interest. -# ---- select-data, include=TRUE, echo=TRUE -x <- ds[, params$model_cols] -head(x, n = 2) - -#' -#' ## Initial parameters -#' The initial parameters, as chosen in the application, are given by -# ---- show-initial-params, include=TRUE, echo=TRUE -theta <- as.theta(params$theta) -print(theta) - -#' -#' ## Model fitting -#' With the data loaded and defined initial parameters, the model is now fitted. -# ---- fit_model, error=TRUE -theta <- fit.full.GMCM(u = x, # Ranking function is applied automatically - theta = theta, - method = params$fit_method, - max.ite = params$max_ite, - verbose = FALSE) -print(theta) - -#' -#' The fitting method is set `r params$fit_method` with a maximum number of iterations of `r params$max_ite`. -#' -#' ## Unsupervised clustering -#' The estimated parameters are used to calculated posterior component probabilities on which the classification is based: -# ---- compute_probs -kappa <- get.prob(x, theta) # Compute component probabilities -colnames(kappa) <- paste0("comp", seq_len(ncol(kappa))) # Add names - -comps <- apply(kappa, 1, which.max) # Find index of maximum entry for each row - -if (params$full_class_type == "thres_prob") { - ok_max <- apply(kappa, 1, max) > params$full_thres_prob - comps[!ok_max] <- NA -} - -cols <- topo.colors(ncol(kappa))[comps] -cols[is.na(comps)] <- "gray" -res <- data.frame(kappa, comp = comps, col = cols, - stringsAsFactors = FALSE) -head(res) -summary(res) - -#' -#' ## Results -#' The classes are counted by -# ---- classes_table -table(res$comp) - -#' The results are also displayed by plotting -# ---- plot_results -plot(x, col = res$col, asp = 1) # Plot of raw values -plot(Uhat(x), col = res$col, asp = 1) # Plot of copula values -z <- GMCM:::qgmm.marginal(Uhat(x), theta = theta) # Estimate latent process -plot(z, col = res$col, asp = 1) # Plot of estimated latent process - - -#' The fitted `theta` object can also be plotted directly: -# ---- plot_theta -plot(theta) - -#' -#' ### Session information -#' This report was generated using **rmarkdown**^[2][2]^ and **knitr**^[3][3]^ under the session -#' given below. The report utilizes [parameterized reports][2] and [`knitr::spin`][3]. -#' -# ---- session-info -sessionInfo() - -#' -#' ### References -#' Please cite the **GMCM** paper^[1][1]^ if you use the package or shiny app. -# ---- citation, echo=FALSE, results='asis' -cites <- lapply(c("GMCM", "knitr", "rmarkdown"), citation) -fmt_cites <- unlist(lapply(cites, format, style = "text")) -cat(paste0(" ", seq_along(fmt_cites), ". ", fmt_cites, "\n")) - - - -#' [1]: http://doi.org/10.18637/jss.v070.i02 -#' [2]: https://bookdown.org/yihui/rmarkdown/parameterized-reports.html -#' [3]: https://yihui.name/knitr/demo/stitch/ diff --git a/inst/shiny/www/report_full.Rmd b/inst/shiny/www/report_full.Rmd new file mode 100644 index 0000000..f583e6c --- /dev/null +++ b/inst/shiny/www/report_full.Rmd @@ -0,0 +1,135 @@ +--- +title: "Unsupervised clustering with general GMCMs" +output: html_document +date: '`r Sys.time()`' +author: "Generated by the GMCM shiny app" +--- + +```{r knit-int, echo=FALSE, include=FALSE} +set.seed(7869670) +``` + + +## Initalisation +The **GMCM**^[1][1]^ package is loaded. + +```{r load-packages, include=TRUE} + +#install.packages("GMCM") # Uncomment to install the GMCM package +library("GMCM") +``` + + +If **GMCM** is *not* installed, please uncomment the above line and rerun the script. + +## Load data +The data is loaded and the first rows are printed + +```{r load-data, include=TRUE, echo=TRUE} +ds <- read.table(file = "{{gsub("\\", "/", data_file, fixed = TRUE)}}", + header = {{header}}, + sep = "{{sep}}", + quote = "\{{quote}}") +head(ds, n = 4) +``` + + +Next, the data is subset to the columns of interest. + +```{r select-data, include=TRUE, echo=TRUE} +x <- ds[, {{cput(model_cols)}}] +head(x, n = 2) +``` + + +## Initial parameters +The initial parameters, as chosen in the application, are given by + +```{r show-initial-params, include=TRUE, echo=TRUE} +theta <- as.theta({{cput(theta)}}) +print(theta) +``` + + +## Model fitting +With the data loaded and defined initial parameters, the model is now fitted. + +```{r fit_model, error=TRUE} +theta <- fit.full.GMCM(u = x, # Ranking function is applied automatically + theta = theta, + method = "{{fit_method}}", + max.ite = {{max_ite}}, + verbose = FALSE) +print(theta) +``` + +The fitting method is set to `"{{fit_method}}"` with a maximum number of iterations of `{{max_ite}}`. + + +## Unsupervised clustering +The estimated parameters are used to calculated posterior component probabilities on which the classification is based: + +```{r compute_probs} +kappa <- get.prob(x, theta) # Compute component probabilities +colnames(kappa) <- paste0("comp", seq_len(ncol(kappa))) # Add names + +comps <- apply(kappa, 1, which.max) # Find index of maximum entry for each row + +{{ifelse(full_class_type == "thres_prob", "# Set to NA if probability is not sufficently large", "")}} +{{ifelse(full_class_type == "thres_prob", sprintf("ok_max <- apply(kappa, 1, max) > %.3f", full_thres_prob), "")}} +{{ifelse(full_class_type == "thres_prob", "comps[!ok_max] <- NA", "")}} + +cols <- topo.colors(ncol(kappa))[comps] +cols[is.na(comps)] <- "gray" +res <- data.frame(kappa, comp = comps, col = cols, + stringsAsFactors = FALSE) +head(res) +summary(res) +``` + + +## Results +The classes are counted by + +```{r classes_table} +table(res$comp) +``` + +The results are also displayed by plotting + +```{r plot_results} +plot(x, col = res$col, asp = 1) # Plot of raw values +plot(Uhat(x), col = res$col, asp = 1) # Plot of copula values +z <- GMCM:::qgmm.marginal(Uhat(x), theta = theta) # Estimate latent process +plot(z, col = res$col, asp = 1) # Plot of estimated latent process +``` + +The fitted `theta` object can also be plotted directly: + +```{r plot_theta} +plot(theta) +``` + + +### Session information +This report was generated using **rmarkdown**^[2][2]^ and **knitr**^[3][3]^ under the session +given below. The report utilizes [parameterized reports][2] and [`knitr::spin`][3]. + + +```{r session-info} +sessionInfo() +``` + + +### References +Please cite the **GMCM** paper^[1][1]^ if you use the package or shiny app. + +```{r citation, echo=FALSE, results='asis'} +cites <- lapply(c("GMCM", "knitr", "rmarkdown"), citation) +fmt_cites <- unlist(lapply(cites, format, style = "text")) +cat(paste0(" ", seq_along(fmt_cites), ". ", fmt_cites, "\n")) +``` + +[1]: http://doi.org/10.18637/jss.v070.i02 +[2]: https://bookdown.org/yihui/rmarkdown/parameterized-reports.html +[3]: https://yihui.name/knitr/demo/stitch/ diff --git a/inst/shiny/www/report_meta.Rmd b/inst/shiny/www/report_meta.Rmd index e758cab..996ff94 100644 --- a/inst/shiny/www/report_meta.Rmd +++ b/inst/shiny/www/report_meta.Rmd @@ -4,20 +4,6 @@ output: html_document date: '`r Sys.time()`' author: "Generated by the GMCM shiny app" --- - - - - - - - - - - - - - - ```{r knit-int, echo=FALSE, include=FALSE} set.seed(5828993) @@ -40,13 +26,14 @@ If **GMCM** is *not* installed, please uncomment the above line and rerun the sc The data is loaded and the first rows are printed ```{r load-data, include=TRUE, echo=TRUE} -ds <- read.table(file = "{{input_file}}", +ds <- read.table(file = "{{gsub("\\", "/", data_file, fixed = TRUE)}}", header = {{header}}, sep = "{{sep}}", quote = "\{{quote}}") head(ds, n = 4) ``` +The reproduce the output, change the file path above to the data file of interest. Next, the data is subset to the columns of interest.