From 81085811d6e8cc8b82c66626667fd356329fa872 Mon Sep 17 00:00:00 2001 From: Kevin Rue-Albrecht Date: Fri, 13 Dec 2019 19:00:05 +0000 Subject: [PATCH 01/10] RStudio addin to define new panels. --- DESCRIPTION | 5 +- NAMESPACE | 3 ++ R/addin.R | 39 ++++++++++++++ inst/rstudio/addins.dcf | 4 ++ inst/scripts/new_panel.R | 44 ++++++++++++++++ inst/templates/NewPanel.R | 106 ++++++++++++++++++++++++++++++++++++++ man/new_panel_file.Rd | 27 ++++++++++ 7 files changed, 226 insertions(+), 2 deletions(-) create mode 100644 R/addin.R create mode 100644 inst/rstudio/addins.dcf create mode 100644 inst/scripts/new_panel.R create mode 100644 inst/templates/NewPanel.R create mode 100644 man/new_panel_file.Rd diff --git a/DESCRIPTION b/DESCRIPTION index fe5a357..6dfd794 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -39,9 +39,10 @@ Suggests: knitr, rmarkdown, BiocStyle, - htmltools + htmltools, + rstudioapi URL: https://github.com/csoneson/iSEEu BugReports: https://github.com/csoneson/iSEEu/issues -RoxygenNote: 7.0.1 +RoxygenNote: 7.0.2 Roxygen: list(markdown = TRUE) VignetteBuilder: knitr diff --git a/NAMESPACE b/NAMESPACE index 97afc44..2806c8d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,7 +2,10 @@ export(modeEmpty) export(modeGating) +export(new_panel_file) importFrom(S4Vectors,DataFrame) importFrom(iSEE,featAssayPlotDefaults) importFrom(iSEE,iSEE) +importFrom(methods,extends) +importFrom(methods,getClasses) importFrom(shiny,runApp) diff --git a/R/addin.R b/R/addin.R new file mode 100644 index 0000000..e1bf17a --- /dev/null +++ b/R/addin.R @@ -0,0 +1,39 @@ +new_panel_addin = function() { + sys.source(system.file(package = 'iSEE', 'scripts', 'new_panel.R')) +} + +#' @importFrom methods extends getClasses +collect_parents <- function() { + x <- getClasses("package:iSEE") + is_panel <- function(Class) { + extends(Class, "Panel") + } + keep <- vapply(x, is_panel, FUN.VALUE = logical(1)) + x[keep] +} + +#' Create a new panel file +#' +#' Opens a template R script in the editor, to define a new iSEE panel class . +#' +#' @param encoded Name of the new panel class. +#' @param decoded Extended name of the new panel class (for display). +#' @param parent Name of the parent panel class +#' +#' @export +#' +#' @author Kevin Rue-Albrecht +#' +#' @seealso \linkS4class{Panel} +#' +#' @examples +#' new_panel_file("NewRedDimPlot", "New reduced dimension plot", "RedDimPlot") +new_panel_file <- function(encoded, decoded, parent="Panel") { + template_file <- system.file(package = "iSEE", "templates", "NewPanel.R") + template_content <- scan(template_file, "character", sep = "\n", quiet = TRUE) + template_content <- paste0(template_content, collapse = "\n") + template_content <- gsub("__ENCODED__", encoded, template_content, fixed = TRUE) + template_content <- gsub("__DECODED__", decoded, template_content, fixed = TRUE) + template_content <- gsub("__PARENT__", parent, template_content, fixed = TRUE) + rstudioapi::documentNew(template_content, type = "r") +} diff --git a/inst/rstudio/addins.dcf b/inst/rstudio/addins.dcf new file mode 100644 index 0000000..61b68d1 --- /dev/null +++ b/inst/rstudio/addins.dcf @@ -0,0 +1,4 @@ +Name: New Panel +Description: Create a new panel class with iSEE::new_panel(). +Binding: new_panel_addin +Interactive: true diff --git a/inst/scripts/new_panel.R b/inst/scripts/new_panel.R new file mode 100644 index 0000000..f465aab --- /dev/null +++ b/inst/scripts/new_panel.R @@ -0,0 +1,44 @@ +local({ + txt_input = function(..., width = '100%') shiny::textInput(..., width = width) + sel_input = function(...) shiny::selectizeInput( + ..., width = '98%', multiple = FALSE, options = list(create = TRUE) + ) + parent_choices = sort(iSEE:::collect_parents()) + shiny::runGadget( + miniUI::miniPage(miniUI::miniContentPanel( + txt_input('encoded', 'Class encoded name', placeholder = 'MyNewPlot'), + txt_input('decoded', 'Class decoded name', placeholder = 'My New Plot'), + shiny::fillRow( + sel_input('parentclass', 'Parent class', parent_choices, selected="Panel"), + height = '70px' + ), + miniUI::gadgetTitleBar(NULL) + )), + server = function(input, output, session) { + + shiny::observeEvent(input$done, { + encoded <- input$encoded + decoded <- input$decoded + parentclass <- input$parentclass + + if (grepl('^\\s*$', encoded)) return( + warning('The decoded class name is empty!', call. = FALSE) + ) + if (grepl('^\\s*$', decoded)) return( + warning('The encoded class name is empty!', call. = FALSE) + ) + if (grepl('^\\s*$', parentclass)) return( + warning('The parent class name is empty!', call. = FALSE) + ) + + iSEE:::new_panel_file(encoded, decoded, parentclass) + shiny::stopApp() + }) + + shiny::observeEvent(input$cancel, { + shiny::stopApp() + }) + }, + stopOnCancel = FALSE, viewer = shiny::dialogViewer('New Post', height = 500) + ) +}) diff --git a/inst/templates/NewPanel.R b/inst/templates/NewPanel.R new file mode 100644 index 0000000..f380725 --- /dev/null +++ b/inst/templates/NewPanel.R @@ -0,0 +1,106 @@ +setClass("__ENCODED__", contains="__PARENT__") + +#' Panel name +#' +#' Panel description +#' +#' @section Constructor: +#' \code{__ENCODED__()} creates an instance of a __ENCODED__ class. +#' +#' @author Author name +#' +#' @examples +#' ################# +#' # For end-users # +#' ################# +#' +#' x <- __ENCODED__() +#' +#' ################## +#' # For developers # +#' ################## +#' +#' +#' library(scater) +#' sce <- mockSCE() +#' sce <- logNormCounts(sce) +#' +#' # Spits out a NULL and a warning if no reducedDims are available. +#' sce0 <- .cacheCommonInfo(x, sce) +#' .refineParameters(x, sce0) +#' +#' # Replaces the default with something sensible. +#' sce <- runPCA(sce) +#' sce0 <- .cacheCommonInfo(x, sce) +#' .refineParameters(x, sce0) +#' +#' @docType methods +#' @aliases __ENCODED__ __ENCODED__-class +#' .defineParamInterface,__ENCODED__-method +#' .createParamObservers,__ENCODED__-method +#' @name __ENCODED__ +NULL + +#' @export +__ENCODED__ <- function() { + new("__ENCODED__") +} + +#' @export +#' @importFrom methods callNextMethod +setMethod("initialize", "__ENCODED__", function(.Object, ...) { + .Object <- callNextMethod(.Object, ...) + .Object +}) + +#' @export +#' @importClassesFrom SingleCellExperiment SingleCellExperiment +#' @importFrom methods callNextMethod +setMethod(".cacheCommonInfo", "__ENCODED__", function(x, se) { + callNextMethod() +}) + +#' @export +#' @importFrom methods callNextMethod +setMethod(".refineParameters", "__ENCODED__", function(x, se) { + x <- callNextMethod() + x +}) + +#' @importFrom S4Vectors setValidity2 +setValidity2("__ENCODED__", function(object) { + msg <- character(0) + + if (length(msg)>0) { + return(msg) + } + TRUE +}) + +#' @export +#' @importFrom methods callNextMethod +setMethod(".defineParamInterface", "__ENCODED__", function(x, se, active_panels) { + callNextMethod() +}) + +#' @export +#' @importFrom methods callNextMethod +setMethod(".createParamObservers", "__ENCODED__", function(x, se, input, session, pObjects, rObjects) { + callNextMethod() +}) + +#' @export +setMethod(".get__ENCODED__", "__ENCODED__", function(x) "__ENCODED__") + +#' @export +setMethod(".getFullName", "__ENCODED__", function(x) "__DECODED__") + +#' @export +setMethod(".getCommandsDataXY", "__ENCODED__", function(x, param_choices) { + callNextMethod() +}) + +#' @export +setMethod(".getCommandsPlot", "__ENCODED__", function(x, param_choices, plot_data, plot_type, labs, is_subsetted, is_downsampled) { + callNextMethod() +}) diff --git a/man/new_panel_file.Rd b/man/new_panel_file.Rd new file mode 100644 index 0000000..290fe9a --- /dev/null +++ b/man/new_panel_file.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/addin.R +\name{new_panel_file} +\alias{new_panel_file} +\title{Create a new panel file} +\usage{ +new_panel_file(encoded, decoded, parent = "Panel") +} +\arguments{ +\item{encoded}{Name of the new panel class.} + +\item{decoded}{Extended name of the new panel class (for display).} + +\item{parent}{Name of the parent panel class} +} +\description{ +Opens a template R script in the editor, to define a new iSEE panel class . +} +\examples{ +new_panel_file("NewRedDimPlot", "New reduced dimension plot", "RedDimPlot") +} +\seealso{ +\linkS4class{Panel} +} +\author{ +Kevin Rue-Albrecht +} From 567c223e033bd866b8bfab043fcf2f00e8baf4d6 Mon Sep 17 00:00:00 2001 From: Kevin Rue-Albrecht Date: Fri, 13 Dec 2019 19:02:37 +0000 Subject: [PATCH 02/10] allow future panels defined in iSEEu as parent classes --- R/addin.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/addin.R b/R/addin.R index e1bf17a..579e096 100644 --- a/R/addin.R +++ b/R/addin.R @@ -4,7 +4,7 @@ new_panel_addin = function() { #' @importFrom methods extends getClasses collect_parents <- function() { - x <- getClasses("package:iSEE") + x <- unique(c(getClasses("package:iSEE"), getClasses("package:iSEEu"))) is_panel <- function(Class) { extends(Class, "Panel") } From 67fc4b3bd0aa68e187fbaaf56c12310e62a85bc7 Mon Sep 17 00:00:00 2001 From: Kevin Rue-Albrecht Date: Fri, 13 Dec 2019 19:06:33 +0000 Subject: [PATCH 03/10] Cleaned up specific leftovers in the template. --- inst/templates/NewPanel.R | 5 ----- 1 file changed, 5 deletions(-) diff --git a/inst/templates/NewPanel.R b/inst/templates/NewPanel.R index f380725..e8b51c2 100644 --- a/inst/templates/NewPanel.R +++ b/inst/templates/NewPanel.R @@ -25,10 +25,6 @@ setClass("__ENCODED__", contains="__PARENT__") #' sce <- mockSCE() #' sce <- logNormCounts(sce) #' -#' # Spits out a NULL and a warning if no reducedDims are available. -#' sce0 <- .cacheCommonInfo(x, sce) -#' .refineParameters(x, sce0) -#' #' # Replaces the default with something sensible. #' sce <- runPCA(sce) #' sce0 <- .cacheCommonInfo(x, sce) @@ -54,7 +50,6 @@ setMethod("initialize", "__ENCODED__", function(.Object, ...) { }) #' @export -#' @importClassesFrom SingleCellExperiment SingleCellExperiment #' @importFrom methods callNextMethod setMethod(".cacheCommonInfo", "__ENCODED__", function(x, se) { callNextMethod() From a432c5db25406fa81a0ccd9055b7b5ea55c64b06 Mon Sep 17 00:00:00 2001 From: Kevin Rue-Albrecht Date: Fri, 13 Dec 2019 19:28:59 +0000 Subject: [PATCH 04/10] update system.file to search template in iSEEu --- R/addin.R | 8 ++++---- inst/rstudio/addins.dcf | 2 +- inst/scripts/new_panel.R | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/R/addin.R b/R/addin.R index 579e096..be466e4 100644 --- a/R/addin.R +++ b/R/addin.R @@ -1,9 +1,9 @@ new_panel_addin = function() { - sys.source(system.file(package = 'iSEE', 'scripts', 'new_panel.R')) + sys.source(system.file(package = 'iSEEu', 'scripts', 'new_panel.R')) } #' @importFrom methods extends getClasses -collect_parents <- function() { +collect_parent_classes <- function() { x <- unique(c(getClasses("package:iSEE"), getClasses("package:iSEEu"))) is_panel <- function(Class) { extends(Class, "Panel") @@ -29,8 +29,8 @@ collect_parents <- function() { #' @examples #' new_panel_file("NewRedDimPlot", "New reduced dimension plot", "RedDimPlot") new_panel_file <- function(encoded, decoded, parent="Panel") { - template_file <- system.file(package = "iSEE", "templates", "NewPanel.R") - template_content <- scan(template_file, "character", sep = "\n", quiet = TRUE) + template_file <- system.file(package = "iSEEu", "templates", "NewPanel.R") + template_content <- scan(template_file, "character", sep = "\n", quiet = TRUE, blank.lines.skip = FALSE) template_content <- paste0(template_content, collapse = "\n") template_content <- gsub("__ENCODED__", encoded, template_content, fixed = TRUE) template_content <- gsub("__DECODED__", decoded, template_content, fixed = TRUE) diff --git a/inst/rstudio/addins.dcf b/inst/rstudio/addins.dcf index 61b68d1..e12a5d1 100644 --- a/inst/rstudio/addins.dcf +++ b/inst/rstudio/addins.dcf @@ -1,4 +1,4 @@ -Name: New Panel +Name: New iSEE Panel Description: Create a new panel class with iSEE::new_panel(). Binding: new_panel_addin Interactive: true diff --git a/inst/scripts/new_panel.R b/inst/scripts/new_panel.R index f465aab..a9a570e 100644 --- a/inst/scripts/new_panel.R +++ b/inst/scripts/new_panel.R @@ -3,7 +3,7 @@ local({ sel_input = function(...) shiny::selectizeInput( ..., width = '98%', multiple = FALSE, options = list(create = TRUE) ) - parent_choices = sort(iSEE:::collect_parents()) + parent_choices = sort(iSEE:::collect_parent_classes()) shiny::runGadget( miniUI::miniPage(miniUI::miniContentPanel( txt_input('encoded', 'Class encoded name', placeholder = 'MyNewPlot'), From a3db5caee31b7a2d1003bdfe8e369b8075a02838 Mon Sep 17 00:00:00 2001 From: Kevin Rue-Albrecht Date: Fri, 13 Dec 2019 19:30:44 +0000 Subject: [PATCH 05/10] Credit where credit is due --- inst/scripts/new_panel.R | 1 + 1 file changed, 1 insertion(+) diff --git a/inst/scripts/new_panel.R b/inst/scripts/new_panel.R index a9a570e..923f5d6 100644 --- a/inst/scripts/new_panel.R +++ b/inst/scripts/new_panel.R @@ -1,3 +1,4 @@ +# Adapted from https://github.com/rstudio/blogdown/blob/master/inst/scripts/new_post.R local({ txt_input = function(..., width = '100%') shiny::textInput(..., width = width) sel_input = function(...) shiny::selectizeInput( From 410bbd5866e7be85135c227317b3d628ee126d0f Mon Sep 17 00:00:00 2001 From: Kevin Rue-Albrecht Date: Fri, 13 Dec 2019 19:50:43 +0000 Subject: [PATCH 06/10] updated internal function call to iSEEu --- R/addin.R | 18 ++++++++++++++++++ inst/scripts/new_panel.R | 2 +- man/.gitignore | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 man/.gitignore diff --git a/R/addin.R b/R/addin.R index be466e4..18fc82b 100644 --- a/R/addin.R +++ b/R/addin.R @@ -1,7 +1,25 @@ +#' New iSEE panel class addin. +#' +#' Runs the addin miniUI to create a new iSEE panel class. +#' +#' @return `NULL`, invisibly. +#' +#' @author Kevin Rue-Albrecht +#' +#' @rdname INTERNAL_new_panel_addin new_panel_addin = function() { sys.source(system.file(package = 'iSEEu', 'scripts', 'new_panel.R')) } +#' List available parent classes for new iSEE panel classes +#' +#' Collects the list of classes - both virtual and concrete - defined in either [iSEE::iSEE-pkg] or `iSEEu`, and that extend the [iSEE::Panel-class]. +#' +#' @return A character vector +#' +#' @author Kevin Rue-Albrecht +#' +#' @rdname INTERNAL_collect_parent_classes #' @importFrom methods extends getClasses collect_parent_classes <- function() { x <- unique(c(getClasses("package:iSEE"), getClasses("package:iSEEu"))) diff --git a/inst/scripts/new_panel.R b/inst/scripts/new_panel.R index 923f5d6..a3e92a1 100644 --- a/inst/scripts/new_panel.R +++ b/inst/scripts/new_panel.R @@ -4,7 +4,7 @@ local({ sel_input = function(...) shiny::selectizeInput( ..., width = '98%', multiple = FALSE, options = list(create = TRUE) ) - parent_choices = sort(iSEE:::collect_parent_classes()) + parent_choices = sort(iSEEu:::collect_parent_classes()) shiny::runGadget( miniUI::miniPage(miniUI::miniContentPanel( txt_input('encoded', 'Class encoded name', placeholder = 'MyNewPlot'), diff --git a/man/.gitignore b/man/.gitignore new file mode 100644 index 0000000..b0abb65 --- /dev/null +++ b/man/.gitignore @@ -0,0 +1 @@ +INTERNAL_* From 5f257d77275bc6f54ba6b38b53a9ab676fa10f66 Mon Sep 17 00:00:00 2001 From: Kevin Rue-Albrecht Date: Fri, 13 Dec 2019 19:51:39 +0000 Subject: [PATCH 07/10] Move another internal call from iSEE to iSEEu --- inst/scripts/new_panel.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/scripts/new_panel.R b/inst/scripts/new_panel.R index a3e92a1..3d03b5e 100644 --- a/inst/scripts/new_panel.R +++ b/inst/scripts/new_panel.R @@ -32,7 +32,7 @@ local({ warning('The parent class name is empty!', call. = FALSE) ) - iSEE:::new_panel_file(encoded, decoded, parentclass) + iSEEu:::new_panel_file(encoded, decoded, parentclass) shiny::stopApp() }) From 8c6370c627178d44c6aaf2658341706e9dd3df2a Mon Sep 17 00:00:00 2001 From: Kevin Rue-Albrecht Date: Fri, 13 Dec 2019 19:52:47 +0000 Subject: [PATCH 08/10] restore syntax from blogdown template --- inst/scripts/new_panel.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/scripts/new_panel.R b/inst/scripts/new_panel.R index 3d03b5e..2c297c0 100644 --- a/inst/scripts/new_panel.R +++ b/inst/scripts/new_panel.R @@ -32,7 +32,7 @@ local({ warning('The parent class name is empty!', call. = FALSE) ) - iSEEu:::new_panel_file(encoded, decoded, parentclass) + iSEEu::new_panel_file(encoded, decoded, parentclass) shiny::stopApp() }) From a47391574de189c2fb195c6547e771150ffe642f Mon Sep 17 00:00:00 2001 From: Kevin Rue-Albrecht Date: Fri, 13 Dec 2019 20:19:25 +0000 Subject: [PATCH 09/10] missing dependency: methods --- DESCRIPTION | 1 + 1 file changed, 1 insertion(+) diff --git a/DESCRIPTION b/DESCRIPTION index 6dfd794..c51c292 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -31,6 +31,7 @@ Encoding: UTF-8 Depends: iSEE Imports: + methods, S4Vectors, shiny Suggests: From a5750ce2327cd86b74011fbabcd661ed845687d2 Mon Sep 17 00:00:00 2001 From: Kevin Rue-Albrecht Date: Fri, 13 Dec 2019 22:16:44 +0000 Subject: [PATCH 10/10] Run example in RStudio only --- R/addin.R | 8 +++++--- man/new_panel_file.Rd | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/R/addin.R b/R/addin.R index 18fc82b..7004b11 100644 --- a/R/addin.R +++ b/R/addin.R @@ -15,7 +15,7 @@ new_panel_addin = function() { #' #' Collects the list of classes - both virtual and concrete - defined in either [iSEE::iSEE-pkg] or `iSEEu`, and that extend the [iSEE::Panel-class]. #' -#' @return A character vector +#' @return A character vector of S4 class names. #' #' @author Kevin Rue-Albrecht #' @@ -30,7 +30,7 @@ collect_parent_classes <- function() { x[keep] } -#' Create a new panel file +#' Create a new panel class file #' #' Opens a template R script in the editor, to define a new iSEE panel class . #' @@ -45,7 +45,9 @@ collect_parent_classes <- function() { #' @seealso \linkS4class{Panel} #' #' @examples -#' new_panel_file("NewRedDimPlot", "New reduced dimension plot", "RedDimPlot") +#' if (Sys.getenv("RSTUDIO") == "1") { +#' new_panel_file("NewRedDimPlot", "New reduced dimension plot", "RedDimPlot") +#' } new_panel_file <- function(encoded, decoded, parent="Panel") { template_file <- system.file(package = "iSEEu", "templates", "NewPanel.R") template_content <- scan(template_file, "character", sep = "\n", quiet = TRUE, blank.lines.skip = FALSE) diff --git a/man/new_panel_file.Rd b/man/new_panel_file.Rd index 290fe9a..7904165 100644 --- a/man/new_panel_file.Rd +++ b/man/new_panel_file.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/addin.R \name{new_panel_file} \alias{new_panel_file} -\title{Create a new panel file} +\title{Create a new panel class file} \usage{ new_panel_file(encoded, decoded, parent = "Panel") } @@ -17,7 +17,9 @@ new_panel_file(encoded, decoded, parent = "Panel") Opens a template R script in the editor, to define a new iSEE panel class . } \examples{ -new_panel_file("NewRedDimPlot", "New reduced dimension plot", "RedDimPlot") +if (Sys.getenv("RSTUDIO") == "1") { + new_panel_file("NewRedDimPlot", "New reduced dimension plot", "RedDimPlot") +} } \seealso{ \linkS4class{Panel}