diff --git a/.github/.gitignore b/.github/.gitignore new file mode 100644 index 0000000..2d19fc7 --- /dev/null +++ b/.github/.gitignore @@ -0,0 +1 @@ +*.html diff --git a/.github/ISSUE_TEMPLATE/issue_template.md b/.github/ISSUE_TEMPLATE/issue_template.md new file mode 100644 index 0000000..6e857c6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue_template.md @@ -0,0 +1,56 @@ +--- +name: Bug report or feature request +about: Describe a bug you've seen or make a case for a new feature +title: "[BUG] Your bug or feature request" +labels: '' +assignees: '' +--- + +Please briefly describe your problem and what output you expect. If you have a question, please don't use this form. Instead, ask on using the appropriate tag(s) including one for this package. + +## Context + +Provide some context for your bug report or feature request. This could be the: + +* link to raw code, example: https://github.com/lcolladotor/osca_LIIGH_UNAM_2020/blob/master/00-template.Rmd#L24-L28 +* link to a commit, example: https://github.com/lcolladotor/osca_LIIGH_UNAM_2020/commit/6aa30b22eda614d932c12997ba611ba582c435d7 +* link to a line of code inside a commit, example: https://github.com/lcolladotor/osca_LIIGH_UNAM_2020/commit/6aa30b22eda614d932c12997ba611ba582c435d7#diff-e265269fe4f17929940e81341b92b116R17 +* link to code from an R package, example: https://github.com/LieberInstitute/spatialLIBD/blob/master/R/run_app.R#L51-L55 + +## Code + +Include the code you ran and comments + +```R +## prompt an error +stop('hola') + +## check the error trace +traceback() +``` + +## Small reproducible example + +If you copy the lines of code that lead to your error, you can then run [`reprex::reprex()`](https://reprex.tidyverse.org/reference/reprex.html) which will create a small website with code you can then easily copy-paste here in a way that will be easy to work with later on. + +```R +## prompt an error +stop('hola') +#> Error in eval(expr, envir, enclos): hola + +## check the error trace +traceback() +#> No traceback available +``` + + +## R session information + +Remember to include your full R session information. + +```R +options(width = 120) +sessioninfo::session_info() +``` + +The output of `sessioninfo::session_info()` includes relevant GitHub installation information and other details that are missed by `sessionInfo()`. diff --git a/.github/workflows/check-bioc.yml b/.github/workflows/check-bioc.yml new file mode 100644 index 0000000..a3e4522 --- /dev/null +++ b/.github/workflows/check-bioc.yml @@ -0,0 +1,270 @@ +## Read more about GitHub actions the features of this GitHub Actions workflow +## at https://lcolladotor.github.io/biocthis/articles/biocthis.html#use_bioc_github_action +## +## For more details, check the biocthis developer notes vignette at +## https://lcolladotor.github.io/biocthis/articles/biocthis_dev_notes.html +## +## You can add this workflow to other packages using: +## > biocthis::use_bioc_github_action() +## +## Using GitHub Actions exposes you to many details about how R packages are +## compiled and installed in several operating system.s +### If you need help, please follow the steps listed at +## https://github.com/r-lib/actions#where-to-find-help +## +## If you found an issue specific to biocthis's GHA workflow, please report it +## with the information that will make it easier for others to help you. +## Thank you! + +## Acronyms: +## * GHA: GitHub Action +## * OS: operating system + +on: + push: + pull_request: + +name: R-CMD-check-bioc + +## These environment variables control whether to run GHA code later on that is +## specific to testthat, covr, and pkgdown. +## +## If you need to clear the cache of packages, update the number inside +## cache-version as discussed at https://github.com/r-lib/actions/issues/86. +## Note that you can always run a GHA test without the cache by using the word +## "/nocache" in the commit message. +env: + has_testthat: 'true' + run_covr: 'true' + run_pkgdown: 'false' + has_RUnit: 'false' + cache-version: 'cache-v1' + +jobs: + build-check: + runs-on: ${{ matrix.config.os }} + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + container: ${{ matrix.config.cont }} + ## Environment variables unique to this job. + + strategy: + fail-fast: false + matrix: + config: + - { os: ubuntu-latest, r: '4.0', bioc: '3.12', cont: "bioconductor/bioconductor_docker:RELEASE_3_12", rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest" } + - { os: macOS-latest, r: '4.0', bioc: '3.12'} + - { os: windows-latest, r: '4.0', bioc: '3.12'} + env: + R_REMOTES_NO_ERRORS_FROM_WARNINGS: true + RSPM: ${{ matrix.config.rspm }} + NOT_CRAN: true + TZ: UTC + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + + steps: + + ## Set the R library to the directory matching the + ## R packages cache step further below when running on Docker (Linux). + - name: Set R Library home on Linux + if: runner.os == 'Linux' + run: | + mkdir /__w/_temp/Library + echo ".libPaths('/__w/_temp/Library')" > ~/.Rprofile + + ## Most of these steps are the same as the ones in + ## https://github.com/r-lib/actions/blob/master/examples/check-standard.yaml + ## If they update their steps, we will also need to update ours. + - name: Checkout Repository + uses: actions/checkout@v2 + + ## R is already included in the Bioconductor docker images + - name: Setup R from r-lib + if: runner.os != 'Linux' + uses: r-lib/actions/setup-r@master + with: + r-version: ${{ matrix.config.r }} + + ## pandoc is already included in the Bioconductor docker images + - name: Setup pandoc from r-lib + if: runner.os != 'Linux' + uses: r-lib/actions/setup-pandoc@master + + - name: Query dependencies + run: | + install.packages('remotes') + saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) + shell: Rscript {0} + + - name: Cache R packages + if: "!contains(github.event.head_commit.message, '/nocache') && runner.os != 'Linux'" + uses: actions/cache@v2 + with: + path: ${{ env.R_LIBS_USER }} + key: ${{ env.cache-version }}-${{ runner.os }}-biocversion-RELEASE_3_12-r-4.0-${{ hashFiles('.github/depends.Rds') }} + restore-keys: ${{ env.cache-version }}-${{ runner.os }}-biocversion-RELEASE_3_12-r-4.0- + + - name: Cache R packages on Linux + if: "!contains(github.event.head_commit.message, '/nocache') && runner.os == 'Linux' " + uses: actions/cache@v2 + with: + path: /home/runner/work/_temp/Library + key: ${{ env.cache-version }}-${{ runner.os }}-biocversion-RELEASE_3_12-r-4.0-${{ hashFiles('.github/depends.Rds') }} + restore-keys: ${{ env.cache-version }}-${{ runner.os }}-biocversion-RELEASE_3_12-r-4.0- + + - name: Install Linux system dependencies + if: runner.os == 'Linux' + run: | + sysreqs=$(Rscript -e 'cat("apt-get update -y && apt-get install -y", paste(gsub("apt-get install -y ", "", remotes::system_requirements("ubuntu", "20.04")), collapse = " "))') + echo $sysreqs + sudo -s eval "$sysreqs" + + - name: Install macOS system dependencies + if: matrix.config.os == 'macOS-latest' + run: | + ## Enable installing XML from source if needed + brew install libxml2 + echo "XML_CONFIG=/usr/local/opt/libxml2/bin/xml2-config" >> $GITHUB_ENV + + ## Required to install magick as noted at + ## https://github.com/r-lib/usethis/commit/f1f1e0d10c1ebc75fd4c18fa7e2de4551fd9978f#diff-9bfee71065492f63457918efcd912cf2 + brew install imagemagick@6 + + ## For textshaping, required by ragg, and required by pkgdown + brew install harfbuzz fribidi + + ## See if this helps get RCurl installed + ## brew uninstall curl + + - name: Install Windows system dependencies + if: runner.os == 'Windows' + run: | + ## Edit below if you have any Windows system dependencies + shell: Rscript {0} + + - name: Install BiocManager + run: | + message(paste('****', Sys.time(), 'installing BiocManager ****')) + remotes::install_cran("BiocManager") + shell: Rscript {0} + + - name: Set BiocVersion + run: | + BiocManager::install(version = "${{ matrix.config.bioc }}", ask = FALSE) + shell: Rscript {0} + + - name: Install dependencies + run: | + ## Try installing the package dependencies in steps. First the local + ## dependencies, then any remaining dependencies to avoid the + ## issues described at + ## https://stat.ethz.ch/pipermail/bioc-devel/2020-April/016675.html + ## https://github.com/r-lib/remotes/issues/296 + ## Ideally, all dependencies should get installed in the first pass. + + ## Temporary for now due to https://github.com/ropensci/RefManageR/issues/79 + remotes::install_github("ropensci/bibtex") + remotes::install_github("ropensci/RefManageR") + remotes::install_github("cboettig/knitcitations") + + ## Pass #1 at installing dependencies + message(paste('****', Sys.time(), 'pass number 1 at installing dependencies: local dependencies ****')) + remotes::install_local(dependencies = TRUE, repos = BiocManager::repositories(), build_vignettes = TRUE, upgrade = TRUE) + + ## Pass #2 at installing dependencies + message(paste('****', Sys.time(), 'pass number 2 at installing dependencies: any remaining dependencies ****')) + remotes::install_local(dependencies = TRUE, repos = BiocManager::repositories(), build_vignettes = TRUE, upgrade = TRUE) + + ## For running the checks + message(paste('****', Sys.time(), 'installing rcmdcheck and BiocCheck ****')) + remotes::install_cran("rcmdcheck") + BiocManager::install("BiocCheck") + shell: Rscript {0} + + - name: Install BiocGenerics + if: env.has_RUnit == 'true' + run: | + ## Install BiocGenerics + BiocManager::install("BiocGenerics") + shell: Rscript {0} + + - name: Install covr + if: github.ref == 'refs/heads/master' && env.run_covr == 'true' && runner.os == 'Linux' + run: | + remotes::install_cran("covr") + shell: Rscript {0} + + - name: Install pkgdown + if: github.ref == 'refs/heads/master' && env.run_pkgdown == 'true' && runner.os == 'Linux' + run: | + remotes::install_cran("pkgdown") + shell: Rscript {0} + + - name: Session info + run: | + options(width = 100) + pkgs <- installed.packages()[, "Package"] + sessioninfo::session_info(pkgs, include_base = TRUE) + shell: Rscript {0} + + - name: Run CMD check + env: + _R_CHECK_CRAN_INCOMING_: false + run: | + rcmdcheck::rcmdcheck( + args = c("--no-build-vignettes", "--no-manual", "--timings"), + build_args = c("--no-manual", "--no-resave-data"), + error_on = "warning", + check_dir = "check" + ) + shell: Rscript {0} + + ## Might need an to add this to the if: && runner.os == 'Linux' + - name: Reveal testthat details + if: env.has_testthat == 'true' + run: find . -name testthat.Rout -exec cat '{}' ';' + + - name: Run RUnit tests + if: env.has_RUnit == 'true' + run: | + BiocGenerics:::testPackage() + shell: Rscript {0} + + - name: Run BiocCheck + run: | + BiocCheck::BiocCheck( + dir('check', 'tar.gz$', full.names = TRUE), + `quit-with-status` = TRUE, + `no-check-R-ver` = TRUE, + `no-check-bioc-help` = TRUE + ) + shell: Rscript {0} + + - name: Test coverage + if: github.ref == 'refs/heads/master' && env.run_covr == 'true' && runner.os == 'Linux' + run: | + covr::codecov() + shell: Rscript {0} + + - name: Install package + if: github.ref == 'refs/heads/master' && env.run_pkgdown == 'true' && runner.os == 'Linux' + run: R CMD INSTALL . + + - name: Deploy package + if: github.ref == 'refs/heads/master' && env.run_pkgdown == 'true' && runner.os == 'Linux' + run: | + git config --local user.email "actions@github.com" + git config --local user.name "GitHub Actions" + Rscript -e "pkgdown::deploy_to_branch(new_process = FALSE)" + shell: bash {0} + ## Note that you need to run pkgdown::deploy_to_branch(new_process = FALSE) + ## at least one locally before this will work. This creates the gh-pages + ## branch (erasing anything you haven't version controlled!) and + ## makes the git history recognizable by pkgdown. + + - name: Upload check results + if: failure() + uses: actions/upload-artifact@master + with: + name: ${{ runner.os }}-biocversion-RELEASE_3_12-r-4.0-results + path: check diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e837ae2..0000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: r -r: bioc-devel -bioc_check: true -cache: - packages: true -sudo: required -warnings_are_errors: false -dist: xenial - -addons: - apt: - update: true - sources: - - sourceline: 'ppa:cran/imagemagick' - packages: - - libmagick++-dev - -after_success: - - Rscript -e 'covr::codecov()' \ No newline at end of file diff --git a/NAMESPACE b/NAMESPACE index 705521a..1dd15c3 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,142 +1,140 @@ -# Generated by roxygen2: do not edit by hand - -export("output_list<-") -export("output_value<-") -export("param_list<-") -export("param_obj<-") -export("param_value<-") -export(DatasetExperiment) -export(as.DatasetExperiment) -export(as.SummarizedExperiment) -export(as.code) -export(as_data_frame) -export(calculate) -export(chart) -export(chart_names) -export(chart_plot) -export(citations) -export(entity) -export(entity_stato) -export(enum) -export(enum_stato) -export(example_chart) -export(example_iterator) -export(example_model) -export(iris_DatasetExperiment) -export(is_output) -export(is_param) -export(iterator) -export(libraries) -export(max_length) -export(metric) -export(model) -export(model_apply) -export(model_predict) -export(model_reverse) -export(model_seq) -export(model_train) -export(models) -export(new_struct) -export(optimiser) -export(output_ids) -export(output_list) -export(output_name) -export(output_obj) -export(output_value) -export(param_ids) -export(param_list) -export(param_name) -export(param_obj) -export(param_value) -export(predicted) -export(predicted_name) -export(preprocess) -export(resampler) -export(result) -export(result_name) -export(run) -export(seq_in) -export(set_obj_method) -export(set_obj_show) -export(set_struct_obj) -export(stato) -export(stato_definition) -export(stato_id) -export(stato_name) -export(stato_summary) -export(struct_class) -export(struct_template) -export(test_metric) -export(value) -exportClasses(struct_class) -exportMethods("$") -exportMethods("$<-") -exportMethods("*") -exportMethods("+") -exportMethods("[") -exportMethods("[<-") -exportMethods("max_length<-") -exportMethods("models<-") -exportMethods("output_list<-") -exportMethods("output_obj<-") -exportMethods("output_value<-") -exportMethods("param_list<-") -exportMethods("param_obj<-") -exportMethods("param_value<-") -exportMethods("predicted_name<-") -exportMethods("result_name<-") -exportMethods("seq_in<-") -exportMethods("value<-") -exportMethods(as.DatasetExperiment) -exportMethods(as.SummarizedExperiment) -exportMethods(as.code) -exportMethods(calculate) -exportMethods(chart_names) -exportMethods(chart_plot) -exportMethods(citations) -exportMethods(evaluate) -exportMethods(export_xlsx) -exportMethods(is_output) -exportMethods(is_param) -exportMethods(length) -exportMethods(libraries) -exportMethods(max_length) -exportMethods(model_apply) -exportMethods(model_predict) -exportMethods(model_reverse) -exportMethods(model_train) -exportMethods(models) -exportMethods(output_ids) -exportMethods(output_list) -exportMethods(output_name) -exportMethods(output_obj) -exportMethods(output_value) -exportMethods(param_ids) -exportMethods(param_list) -exportMethods(param_name) -exportMethods(param_obj) -exportMethods(param_value) -exportMethods(predicted) -exportMethods(predicted_name) -exportMethods(result) -exportMethods(result_name) -exportMethods(run) -exportMethods(seq_in) -exportMethods(stato_definition) -exportMethods(stato_id) -exportMethods(stato_name) -exportMethods(stato_summary) -exportMethods(value) -import(S4Vectors) -import(SummarizedExperiment) -import(datasets) -import(methods) -importFrom(graphics,plot) -importFrom(knitr,purl) -importFrom(ontologyIndex,get_ontology) -importFrom(stats,runif) -importFrom(utils,as.person) -importFrom(utils,bibentry) -importFrom(utils,capture.output) -importFrom(utils,citation) -importFrom(utils,file.edit) +export("output_list<-") +export("output_value<-") +export("param_list<-") +export("param_obj<-") +export("param_value<-") +export(DatasetExperiment) +export(as.DatasetExperiment) +export(as.SummarizedExperiment) +export(as.code) +export(as_data_frame) +export(calculate) +export(chart) +export(chart_names) +export(chart_plot) +export(citations) +export(entity) +export(entity_stato) +export(enum) +export(enum_stato) +export(example_chart) +export(example_iterator) +export(example_model) +export(iris_DatasetExperiment) +export(is_output) +export(is_param) +export(iterator) +export(libraries) +export(max_length) +export(metric) +export(model) +export(model_apply) +export(model_predict) +export(model_reverse) +export(model_seq) +export(model_train) +export(models) +export(new_struct) +export(optimiser) +export(output_ids) +export(output_list) +export(output_name) +export(output_obj) +export(output_value) +export(param_ids) +export(param_list) +export(param_name) +export(param_obj) +export(param_value) +export(predicted) +export(predicted_name) +export(preprocess) +export(resampler) +export(result) +export(result_name) +export(run) +export(seq_in) +export(set_obj_method) +export(set_obj_show) +export(set_struct_obj) +export(stato) +export(stato_definition) +export(stato_id) +export(stato_name) +export(stato_summary) +export(struct_class) +export(struct_template) +export(test_metric) +export(value) +exportClasses(struct_class) +exportMethods("$") +exportMethods("$<-") +exportMethods("*") +exportMethods("+") +exportMethods("[") +exportMethods("[<-") +exportMethods("max_length<-") +exportMethods("models<-") +exportMethods("output_list<-") +exportMethods("output_obj<-") +exportMethods("output_value<-") +exportMethods("param_list<-") +exportMethods("param_obj<-") +exportMethods("param_value<-") +exportMethods("predicted_name<-") +exportMethods("result_name<-") +exportMethods("seq_in<-") +exportMethods("value<-") +exportMethods(as.DatasetExperiment) +exportMethods(as.SummarizedExperiment) +exportMethods(as.code) +exportMethods(calculate) +exportMethods(chart_names) +exportMethods(chart_plot) +exportMethods(citations) +exportMethods(evaluate) +exportMethods(export_xlsx) +exportMethods(is_output) +exportMethods(is_param) +exportMethods(length) +exportMethods(libraries) +exportMethods(max_length) +exportMethods(model_apply) +exportMethods(model_predict) +exportMethods(model_reverse) +exportMethods(model_train) +exportMethods(models) +exportMethods(output_ids) +exportMethods(output_list) +exportMethods(output_name) +exportMethods(output_obj) +exportMethods(output_value) +exportMethods(param_ids) +exportMethods(param_list) +exportMethods(param_name) +exportMethods(param_obj) +exportMethods(param_value) +exportMethods(predicted) +exportMethods(predicted_name) +exportMethods(result) +exportMethods(result_name) +exportMethods(run) +exportMethods(seq_in) +exportMethods(stato_definition) +exportMethods(stato_id) +exportMethods(stato_name) +exportMethods(stato_summary) +exportMethods(value) +import(S4Vectors) +import(SummarizedExperiment) +import(datasets) +import(methods) +importFrom(graphics,plot) +importFrom(knitr,purl) +importFrom(ontologyIndex,get_ontology) +importFrom(stats,runif) +importFrom(utils,as.person) +importFrom(utils,bibentry) +importFrom(utils,capture.output) +importFrom(utils,citation) +importFrom(utils,file.edit) \ No newline at end of file diff --git a/R/model_class.R b/R/model_class.R index f067c4d..0f8bfdf 100644 --- a/R/model_class.R +++ b/R/model_class.R @@ -1,313 +1,313 @@ -#' model class -#' -#' A class for models that can be trained/applied to datasets e.g. PCA, PLS etc. -#' Also used for preprocessing steps that require application to test sets. -#' not intended to be called directly, this class should be inherited to provide -#' functionality for method-specific classes. -#' -#' @section \code{predicted} slot: -#' The "predicted" slot is a slots for use by users to control the flow of model -#' sequences. The \code{predicted()} function is used to return a default output and -#' from a model. Typically it is a DatasetExperiment object that is passed directly -#' into the next model in a sequence as the data for that model. -#' -#' @section \code{seq_in} slot: -#' In a sequence of models (see model_seq) the "predicted" slot is connected to the -#' DatasetExperiment input of the next model. \code{seq_in} can be used to control -#' flow and connect the "predicted" output to the input parameter of the next model. -#' Default is the keyword 'data', and can otherwise be replaced by any input slot -#' from the model. The slot \code{seq_fcn} can be used to apply a transformation to -#' the output before it is used as an input. This allows you to e.g. convert between types, -#' extract a single column from a data.frame etc. -#' -#' -#' @export model -#' @param M A struct model object -#' @param D A DatasetExperiment object -#' @param value The value to assign -#' @param predicted The name of an output slot to return when using \code{predicted()} (see details) -#' @param seq_in the name of an output slot to connect with the "predicted" output -#' of another model (see details) -#' @param seq_fcn a function to apply to seq_in before inputting into the next model. -#' Typically used to extract a single column, or convert from factor to char etc. -#' @include generics.R parameter_class.R output_class.R -#' @examples -#' M = model() -#' @param ... named slots and their values. -#' @rdname model -model = function(predicted=character(0),seq_in='data',seq_fcn=function(x){return(x)},...) { - # new object - out = .model(predicted = predicted, - seq_in = seq_in, - seq_fcn = seq_fcn, - ...) - return(out) -} - -.model<-setClass( - "model", - contains = c('struct_class'), - slots = c( - predicted = 'character', - seq_in = 'character', - seq_fcn = 'function' - ), - prototype = list( - seq_in = 'data', - seq_fcn=function(x){return(x)} - ) -) - -#' @rdname model -#' @export -#' @examples -#' D = DatasetExperiment() -#' M = model() -#' M = model_train(M,D) -#' @return trained model object -setMethod(f = "model_train", - signature = c("model","DatasetExperiment"), - definition = function(M,D) { - warning('no training implemented for this model') - return(M) - } -) - -#' @rdname model -#' @export -#' @examples -#' D = DatasetExperiment() -#' M = model() -#' M = model_train(M,D) -#' M = model_predict(M,D) -#' @return model object with test set results -setMethod(f = "model_predict", - signature = c("model","DatasetExperiment"), - definition = function(M,D) { - return(M) - } -) - -#' @rdname model -#' @export -#' @examples -#' D = DatasetExperiment() -#' M = model() -#' M = model_apply(M,D) -#' @return trained model object -setMethod(f = "model_apply", - signature = c("model","DatasetExperiment"), - definition = function(M,D) { - M = model_train(M,D) - M = model_predict(M,D) - return(M) - } -) - -#' @rdname model -#' @export -#' @examples -#' D = DatasetExperiment() -#' M = model() -#' M = model_train(M,D) -#' M = model_predict(M,D) -#' M = model_reverse(M,D) -#' @return dataset dataset object with the reverse model applied -setMethod(f = "model_reverse", - signature = c("model","DatasetExperiment"), - definition = function(M,D) { - return(D) - } -) - -#' @rdname model -#' @export -#' @examples -#' D = DatasetExperiment() -#' M = example_model() -#' M = model_train(M,D) -#' M = model_predict(M,D) -#' p = predicted(M) -#' @return the predicted output, as specified by predicted_name -setMethod(f = 'predicted', - signature = c('model'), - definition = function(M) { - if (length(predicted_name(M))==0) { - warning('"predicted" has not been set') - return(NA) - } - if (is.na(predicted_name(M))) { - warning('"predicted" is set to NA') - return(NA) - } - if (is.null(predicted_name(M))) { - warning('"predicted" is set to NULL') - return(NA) - - } - # we can try to return the slot - return(output_value(M,predicted_name(M))) - } - -) - -#' @rdname model -#' @export -#' @examples -#' D = DatasetExperiment() -#' M = example_model() -#' seq_in(M) = 'data' -#' @return the id of the input parameter to be replaced by the \code{predicted} -#' output of the previous model in a model sequence. Reserved keyword 'data' -#' means that the input data used by \code{model_train}, \code{model_apply} etc is used. -#' \code{seq_in = 'data'} is the default setting. -setMethod(f = 'seq_in', - signature = c('model'), - definition = function(M) { - return(M@seq_in) - } - -) - -#' @rdname model -#' @export -#' @examples -#' M = example_model() -#' seq_in(M) = 'value_1' -#' @return the modified model object -setMethod(f = 'seq_in<-', - signature = c('model','character'), - definition = function(M,value) { - if (value %in% param_ids(M) | value=='data') { - M@seq_in = value - } else { - stop(paste0('"', value, '" is not a valid input parameter id for', - ' a '), class(M)[1], ' object.') - } - return(M) - } -) - -#' @rdname model -#' @export -#' @examples -#' M = example_model() -#' predicted_name(M) -#' @return the id of the output returned by predicted() -setMethod(f = 'predicted_name', - signature = c('model'), - definition = function(M) { - return(M@predicted) - } -) - -#' @rdname model -#' @export -#' @examples -#' M = example_model() -#' predicted_name(M) = 'result_2' -#' @return the modified model object -setMethod(f = 'predicted_name<-', - signature = c('model','character'), - definition = function(M,value) { - if (value %in% output_ids(M)) { - M@predicted = value - } else { - stop(paste0('"', value, '" is not a valid output id for', - ' a '), class(M), ' object.') - } - return(M) - } -) - -setMethod(f = "show", - signature = c("model"), - definition = function(object) { - callNextMethod() - cat('predicted: ',predicted_name(object),'\n',sep = '') - cat('seq_in: ',object@seq_in, '\n',sep = '') - cat('\n') - } -) - - -#' @rdname as.code -#' @export -#' @examples -#' M = example_model() -#' as.code(M) -#' @return a string of code to reproduce the model -setMethod(f = 'as.code', - signature = c('model'), - definition = function(M,start = 'M = ',mode = 'compact') { - .as_code(M,start,mode) - } -) - - - -.as_code = function(M,start='M = ',mode = 'compact') { - - if (!(mode %in% c('compact','neat','expanded','full'))) { - stop(paste0('unknown option "', mode , '" for as.code()')) - } - str=start - # model object name - str=paste0(str,class(M)[1],'(') - - # parameters - P = param_ids(M) - - # add seq_in if not equal to data - if (is(M,'model')) { - if (M@seq_in != 'data' | mode=='full') { - P=c(P,'seq_in') - } - } - # add predicted if its not the default - if (is(M,'model')) { - N=new_struct(class(M)[1]) - if (predicted_name(N) != predicted_name(M) | mode=='full') { - P=c(P,'predicted') - } - } - - if (mode != "compact") { - str=paste0(str,'\n') - indent=nchar(start)+2 - } else { - indent=(nchar(start)+1)+nchar(class(M)[1]) - } - - for (p in seq_len(length(P))) { - if (p>1 | mode!="compact") { - str=paste0(str,paste0(rep(' ',indent),collapse='')) - } - - if (P[p]=='seq_in') { - str=paste0(str,P[p], ' = "', seq_in(M), '"') - } else if (P[p]=='predicted') { - str=paste0(str,P[p], ' = "', predicted_name(M), '"') - } else if (is(param_value(M,P[p]),'character')) { - str=paste0(str,P[p], ' = "', as.character(param_value(M,P[p])), '"') - } else { - str=paste0(str,P[p], ' = ', as.character(param_value(M,P[p]))) - } - - - if (p==length(P)) { - if (mode=='expanded') { - str=paste0(str,'\n',paste0(rep(' ',indent-2),collapse='')) - } - - - str=paste0(str,')') - - - } else { - str=paste0(str,',\n') - } - } - - return(str) +#' model class +#' +#' A class for models that can be trained/applied to datasets e.g. PCA, PLS etc. +#' Also used for preprocessing steps that require application to test sets. +#' not intended to be called directly, this class should be inherited to provide +#' functionality for method-specific classes. +#' +#' @section \code{predicted} slot: +#' The "predicted" slot is a slots for use by users to control the flow of model +#' sequences. The \code{predicted()} function is used to return a default output and +#' from a model. Typically it is a DatasetExperiment object that is passed directly +#' into the next model in a sequence as the data for that model. +#' +#' @section \code{seq_in} slot: +#' In a sequence of models (see model_seq) the "predicted" slot is connected to the +#' DatasetExperiment input of the next model. \code{seq_in} can be used to control +#' flow and connect the "predicted" output to the input parameter of the next model. +#' Default is the keyword 'data', and can otherwise be replaced by any input slot +#' from the model. The slot \code{seq_fcn} can be used to apply a transformation to +#' the output before it is used as an input. This allows you to e.g. convert between types, +#' extract a single column from a data.frame etc. +#' +#' +#' @export model +#' @param M A struct model object +#' @param D A DatasetExperiment object +#' @param value The value to assign +#' @param predicted The name of an output slot to return when using \code{predicted()} (see details) +#' @param seq_in the name of an output slot to connect with the "predicted" output +#' of another model (see details) +#' @param seq_fcn a function to apply to seq_in before inputting into the next model. +#' Typically used to extract a single column, or convert from factor to char etc. +#' @include generics.R parameter_class.R output_class.R +#' @examples +#' M = model() +#' @param ... named slots and their values. +#' @rdname model +model = function(predicted=character(0),seq_in='data',seq_fcn=function(x){return(x)},...) { + # new object + out = .model(predicted = predicted, + seq_in = seq_in, + seq_fcn = seq_fcn, + ...) + return(out) +} + +.model<-setClass( + "model", + contains = c('struct_class'), + slots = c( + predicted = 'character', + seq_in = 'character', + seq_fcn = 'function' + ), + prototype = list( + seq_in = 'data', + seq_fcn=function(x){return(x)} + ) +) + +#' @rdname model +#' @export +#' @examples +#' D = DatasetExperiment() +#' M = model() +#' M = model_train(M,D) +#' @return trained model object +setMethod(f = "model_train", + signature = c("model","DatasetExperiment"), + definition = function(M,D) { + warning('no training implemented for this model') + return(M) + } +) + +#' @rdname model +#' @export +#' @examples +#' D = DatasetExperiment() +#' M = model() +#' M = model_train(M,D) +#' M = model_predict(M,D) +#' @return model object with test set results +setMethod(f = "model_predict", + signature = c("model","DatasetExperiment"), + definition = function(M,D) { + return(M) + } +) + +#' @rdname model +#' @export +#' @examples +#' D = DatasetExperiment() +#' M = model() +#' M = model_apply(M,D) +#' @return trained model object +setMethod(f = "model_apply", + signature = c("model","DatasetExperiment"), + definition = function(M,D) { + M = model_train(M,D) + M = model_predict(M,D) + return(M) + } +) + +#' @rdname model +#' @export +#' @examples +#' D = DatasetExperiment() +#' M = model() +#' M = model_train(M,D) +#' M = model_predict(M,D) +#' M = model_reverse(M,D) +#' @return dataset dataset object with the reverse model applied +setMethod(f = "model_reverse", + signature = c("model","DatasetExperiment"), + definition = function(M,D) { + return(D) + } +) + +#' @rdname model +#' @export +#' @examples +#' D = DatasetExperiment() +#' M = example_model() +#' M = model_train(M,D) +#' M = model_predict(M,D) +#' p = predicted(M) +#' @return the predicted output, as specified by predicted_name +setMethod(f = 'predicted', + signature = c('model'), + definition = function(M) { + if (length(predicted_name(M))==0) { + warning('"predicted" has not been set') + return(NA) + } + if (is.na(predicted_name(M))) { + warning('"predicted" is set to NA') + return(NA) + } + if (is.null(predicted_name(M))) { + warning('"predicted" is set to NULL') + return(NA) + + } + # we can try to return the slot + return(output_value(M,predicted_name(M))) + } + +) + +#' @rdname model +#' @export +#' @examples +#' D = DatasetExperiment() +#' M = example_model() +#' seq_in(M) = 'data' +#' @return the id of the input parameter to be replaced by the \code{predicted} +#' output of the previous model in a model sequence. Reserved keyword 'data' +#' means that the input data used by \code{model_train}, \code{model_apply} etc is used. +#' \code{seq_in = 'data'} is the default setting. +setMethod(f = 'seq_in', + signature = c('model'), + definition = function(M) { + return(M@seq_in) + } + +) + +#' @rdname model +#' @export +#' @examples +#' M = example_model() +#' seq_in(M) = 'value_1' +#' @return the modified model object +setMethod(f = 'seq_in<-', + signature = c('model','character'), + definition = function(M,value) { + if (value %in% param_ids(M) | value=='data') { + M@seq_in = value + } else { + stop(paste0('"', value, '" is not a valid input parameter id for', + ' a '), class(M)[1], ' object.') + } + return(M) + } +) + +#' @rdname model +#' @export +#' @examples +#' M = example_model() +#' predicted_name(M) +#' @return the id of the output returned by predicted() +setMethod(f = 'predicted_name', + signature = c('model'), + definition = function(M) { + return(M@predicted) + } +) + +#' @rdname model +#' @export +#' @examples +#' M = example_model() +#' predicted_name(M) = 'result_2' +#' @return the modified model object +setMethod(f = 'predicted_name<-', + signature = c('model','character'), + definition = function(M,value) { + if (value %in% output_ids(M)) { + M@predicted = value + } else { + stop(paste0('"', value, '" is not a valid output id for', + ' a '), class(M), ' object.') + } + return(M) + } +) + +setMethod(f = "show", + signature = c("model"), + definition = function(object) { + callNextMethod() + cat('predicted: ',predicted_name(object),'\n',sep = '') + cat('seq_in: ',object@seq_in, '\n',sep = '') + cat('\n') + } +) + + +#' @rdname as.code +#' @export +#' @examples +#' M = example_model() +#' as.code(M) +#' @return a string of code to reproduce the model +setMethod(f = 'as.code', + signature = c('model'), + definition = function(M,start = 'M = ',mode = 'compact') { + .as_code(M,start,mode) + } +) + + + +.as_code = function(M,start='M = ',mode = 'compact') { + + if (!(mode %in% c('compact','neat','expanded','full'))) { + stop(paste0('unknown option "', mode , '" for as.code()')) + } + str=start + # model object name + str=paste0(str,class(M)[1],'(') + + # parameters + P = param_ids(M) + + # add seq_in if not equal to data + if (is(M,'model')) { + if (M@seq_in != 'data' | mode=='full') { + P=c(P,'seq_in') + } + } + # add predicted if its not the default + if (is(M,'model')) { + N=new_struct(class(M)[1]) + if (predicted_name(N) != predicted_name(M) | mode=='full') { + P=c(P,'predicted') + } + } + + if (mode != "compact") { + str=paste0(str,'\n') + indent=nchar(start)+2 + } else { + indent=(nchar(start)+1)+nchar(class(M)[1]) + } + + for (p in seq_len(length(P))) { + if (p>1 | mode!="compact") { + str=paste0(str,paste0(rep(' ',indent),collapse='')) + } + + if (P[p]=='seq_in') { + str=paste0(str,P[p], ' = "', seq_in(M), '"') + } else if (P[p]=='predicted') { + str=paste0(str,P[p], ' = "', predicted_name(M), '"') + } else if (is(param_value(M,P[p]),'character')) { + str=paste0(str,P[p], ' = "', as.character(param_value(M,P[p])), '"') + } else { + str=paste0(str,P[p], ' = ', as.character(param_value(M,P[p]))) + } + + + if (p==length(P)) { + if (mode=='expanded') { + str=paste0(str,'\n',paste0(rep(' ',indent-2),collapse='')) + } + + + str=paste0(str,')') + + + } else { + str=paste0(str,',\n') + } + } + + return(str) } \ No newline at end of file diff --git a/README.rst b/README.rst index 6b751ad..5e8e1af 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ STRUCT: STatistics in R Using Class Templates ============================================== -|Git| |Bioconda| |Build Status (Travis)| |License| |Coverage| |AppVeyor| +|Git| |Bioconda| |Build Status| |License| |Coverage| ------------ @@ -32,14 +32,11 @@ References ------------ -.. |Build Status (Travis)| image:: https://img.shields.io/travis/computational-metabolomics/struct/master.svg?label=Travis - :target: https://travis-ci.org/computational-metabolomics/struct - -.. |Build Status (AppVeyor)| image:: https://ci.appveyor.com/api/projects/status/github/computational-metabolomics/struct?branch=master&svg=true - :target: https://ci.appveyor.com/project/computational-metabolomcis/struct +.. |Build Status| image:: https://github.com/computational-metabolomics/structToolbox/workflows/struct/badge.svg + :target: https://github.com/computational-metabolomics/struct/actions .. |Git| image:: https://img.shields.io/badge/repository-GitHub-blue.svg?style=flat&maxAge=3600 - :target: https://github.com/computational-metabolomics/struct + :target: https://github.com/computational-metabolomics/structToolbox .. |Bioconda| image:: https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg?style=flat&maxAge=3600 :target: https://bioconda.github.io/recipes/bioconductor-struct/README.html @@ -49,6 +46,3 @@ References .. |Coverage| image:: https://codecov.io/gh/computational-metabolomics/struct/branch/master/graph/badge.svg :target: https://codecov.io/gh/computational-metabolomics/struct - -.. |AppVeyor| image:: https://ci.appveyor.com/api/projects/status/github/computational-metabolomics/struct?branch=master&svg=true - :target: https://ci.appveyor.com/project/RJMW/struct diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 096e5c4..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,55 +0,0 @@ -# DO NOT CHANGE the "init" and "install" sections below - -# Download script file from GitHub -init: - ps: | - $ErrorActionPreference = "Stop" - Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" - Import-Module '..\appveyor-tool.ps1' -install: - ps: Bootstrap - -cache: - #- C:\RLibrary - -environment: - NOT_CRAN: true - # env vars that may need to be set, at least temporarily, from time to time - # see https://github.com/krlmlr/r-appveyor#readme for details - # USE_RTOOLS: true - # R_REMOTES_STANDALONE: true - R_VERSION: devel - BIOC_USE_DEVEL: TRUE - USE_RTOOLS: true - PKGTYPE: both - -# Adapt as necessary starting from here - -build_script: - - travis-tool.sh install_deps - -test_script: - - travis-tool.sh run_tests - -on_failure: - - 7z a failure.zip *.Rcheck\* - - appveyor PushArtifact failure.zip - -artifacts: - - path: '*.Rcheck\**\*.log' - name: Logs - - - path: '*.Rcheck\**\*.out' - name: Logs - - - path: '*.Rcheck\**\*.fail' - name: Logs - - - path: '*.Rcheck\**\*.Rout' - name: Logs - - - path: '\*_*.tar.gz' - name: Bits - - - path: '\*_*.zip' - name: Bits \ No newline at end of file