diff --git a/DESCRIPTION b/DESCRIPTION index b472fac..be043ad 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -84,6 +84,7 @@ Collate: 'filter_labels_class.R' 'filter_na_class.R' 'filter_range_class.R' + 'filter_records_class.R' 'filter_venn_class.R' 'github_file_class.R' 'go_database_class.R' diff --git a/NAMESPACE b/NAMESPACE index 1f765c1..f36ac74 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -51,6 +51,7 @@ export(excel_database) export(filter_labels) export(filter_na) export(filter_range) +export(filter_records) export(filter_venn) export(github_file) export(hmdb_lookup) @@ -88,6 +89,7 @@ export(split_records) export(sqlite_database) export(trim_whitespace) export(unique_records) +export(wherever) exportMethods(chart_plot) exportMethods(check_for_columns) exportMethods(is_writable) @@ -104,6 +106,13 @@ import(ggplot2) import(ggthemes) import(httr) import(methods) +import(patchwork) import(rlang) +import(struct) importFrom(scales,manual_pal) +importFrom(utils,URLencode) importFrom(utils,capture.output) +importFrom(utils,modifyList) +importFrom(utils,read.csv) +importFrom(utils,stack) +importFrom(utils,unzip) diff --git a/R/BiocFileCache_database_class.R b/R/BiocFileCache_database_class.R index ebb5ba9..03383b8 100644 --- a/R/BiocFileCache_database_class.R +++ b/R/BiocFileCache_database_class.R @@ -159,11 +159,15 @@ setMethod( field = "rtype", query = "web" )$rid) { # TRUE if newly added or stale - update <- BiocFileCache::bfcneedsupdate(bfc, rid) + update = BiocFileCache::bfcneedsupdate(bfc, rid) + if (is.na(update)) { # FALSE if NA + update=FALSE + } } else { - update <- FALSE # cant update if not web resource + update = FALSE # cant update if not web resource } - + + # download & unzip if (update & !obj$offline) { BiocFileCache::bfcdownload( diff --git a/R/MetMashR-package.R b/R/MetMashR-package.R index a65cf64..bd6bb35 100644 --- a/R/MetMashR-package.R +++ b/R/MetMashR-package.R @@ -1,3 +1,6 @@ +#' @import struct +#' @import patchwork +#' @importFrom utils URLencode modifyList read.csv stack unzip #' @keywords internal "_PACKAGE" diff --git a/R/combine_records_class.R b/R/combine_records_class.R index cfc47fb..4106b3e 100644 --- a/R/combine_records_class.R +++ b/R/combine_records_class.R @@ -402,6 +402,7 @@ NULL #' values. #' @param digits (numeric) the number of digits to use when converting numerical #' values to characters when determining if values are unique. +#' @param sort (logical) sort the values before collapsing. #' @examples #' #' # Collapse unique values @@ -410,11 +411,14 @@ NULL #' default_fcn = .unique( #' digits = 6, #' separator = ", ", -#' na_string = "NA" +#' na_string = "NA", +#' sort = FALSE #' ) #' ) #' @export -.unique <- function(separator, na_string = "NA", digits = 6, drop_na = FALSE) { +.unique <- function(separator, na_string = "NA", digits = 6, drop_na = FALSE, + sort = FALSE + ) { fcn <- expr(function(x) { if (is.numeric(x)) { x <- round(as.numeric(x), !!digits) @@ -430,6 +434,9 @@ NULL x[is.na(x)] <- !!na_string x <- unique(x) + if (sort){ + x=sort(x) + } paste0(x, collapse = !!separator) }) return(eval(fcn)) diff --git a/R/filter_records_class.R b/R/filter_records_class.R new file mode 100644 index 0000000..e2c1aef --- /dev/null +++ b/R/filter_records_class.R @@ -0,0 +1,104 @@ +#' Filter helper function to select records +#' +#' Returns a list of quosures for use with +#' `filter_records` to allow the use of dplyr-style expressions. See examples. +#' +#' @param ... Expressions that return a logical value and are defined in terms +#' of the columns in the annotation_source. If multiple conditions are +#' included then they are combined with the `&` operator. Only records +#' for which all conditions evaluate to `TRUE` are kept. +#' +#' @examples +#' # some annotation data +#' AN = annotation_source(data = iris) +#' +#' # filter to setosa where Sepal length is less than 5 +#' M = filter_records( +#' wherever( +#' Species == 'setosa', +#' Sepal.Length<5 +#' ) +#' ) +#' M = model_apply(M,AN) +#' predicted(M) # 20 rows +#' +#' @returns a list of quosures for use with `filter_records` +#' @seealso [filter_records()] +#' @export +wherever = function(...){ + Q = quos(..., .ignore_empty = "all") + return(Q) +} + +#' @eval get_description('filter_records') +#' @export +#' @include annotation_source_class.R +#' @seealso [dplyr::filter()] +#' @seealso [wherever()] +#' @import rlang +filter_records <- function(where = wherever(A>0), ...) { + + out <- struct::new_struct( + "filter_records", + where = where, + ... + ) + return(out) +} + + +.filter_records <- setClass( + "filter_records", + contains = c("model"), + slots = c( + updated = "entity", + where = "entity" + ), + prototype = list( + name = "Filter rows", + description = paste0( + "A wrapper around [`dplyr::filter`]. Select rows ", + "from an annotation table using tidy grammar." + ), + type = "filter", + predicted = "updated", + .params = c("where"), + .outputs = c("updated"), + libraries = c("dplyr", "rlang"), + updated = entity( + name = "Updated annotations", + description = paste0( + "The updated annotations as an `annotation_source` object" + ), + type = "annotation_source" + ), + where = entity( + name = "Select rows expression", + description = paste0( + 'A list of [`rlang::quosure`] for evaluation e.g. A>10 will', + 'select all rows where the values in column A are greater than', + '10. A helper function [`wherever`] is provided to generate', + 'a suitable list of quosures.' + ), + value = quos(A>10), + type = 'quosures' + ) + ) +) + + +#' @export +setMethod( + f = "model_apply", + signature = c("filter_records", "annotation_source"), + definition = function(M, D) { + + q = M$where + + D$data = filter(.data = D$data,!!!q) + + M$updated = D + + return(M) + } +) diff --git a/R/hmdb_lookup_class.R b/R/hmdb_lookup_class.R index 7452b41..e1a22eb 100644 --- a/R/hmdb_lookup_class.R +++ b/R/hmdb_lookup_class.R @@ -1,10 +1,11 @@ #' @eval get_description('hmdb_lookup') #' @export #' @include annotation_source_class.R rest_api_class.R -hmdb_lookup <- function(query_column, - suffix = "_hmdb", - output = "inchikey", - ...) { +hmdb_lookup <- function( + query_column, + suffix = "_hmdb", + output = "inchikey", + ...) { out <- struct::new_struct( "hmdb_lookup", query_column = query_column, @@ -12,7 +13,7 @@ hmdb_lookup <- function(query_column, output = output, ... ) - + return(out) } diff --git a/R/select_columns_class.R b/R/select_columns_class.R index 04a737c..4c48cca 100644 --- a/R/select_columns_class.R +++ b/R/select_columns_class.R @@ -64,13 +64,13 @@ setMethod( signature = c("select_columns", "annotation_source"), definition = function(M, D) { # column indexes matching expression - loc <- tidyselect::eval_select(M$expression, data = D$data) + loc = tidyselect::eval_select(M$expression, data = D$data) # update names - D$data <- rlang::set_names(D$data[loc], names(loc)) + D$data = rlang::set_names(D$data[loc], names(loc)) # update object - M$updated <- D + M$updated = D return(M) } diff --git a/R/zzz.R b/R/zzz.R index 10624e8..37a9819 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -78,5 +78,8 @@ get_description <- function(id) { str <- gsub("[a annotation_source]", "annotation_source()", str, fixed = TRUE ) + str <- gsub("[a quosures]", "wherever(A>10)", str, + fixed = TRUE + ) return(str) } diff --git a/_pkgdown.yml b/_pkgdown.yml index eb88453..bc3a471 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -88,6 +88,7 @@ reference: - filter_range - filter_na - filter_venn + - filter_records - id_counts - mz_match - rt_match @@ -154,6 +155,7 @@ reference: contents: - check_for_columns - required_cols + - wherever home: links: - text: View on Bioconductor diff --git a/man/combine_records_helper_functions.Rd b/man/combine_records_helper_functions.Rd index 0809e30..b021e60 100644 --- a/man/combine_records_helper_functions.Rd +++ b/man/combine_records_helper_functions.Rd @@ -33,7 +33,7 @@ .select_exact(match_col, match, separator, na_string = "NA") -.unique(separator, na_string = "NA", digits = 6, drop_na = FALSE) +.unique(separator, na_string = "NA", digits = 6, drop_na = FALSE, sort = FALSE) .prioritise(match_col, priority, separator, no_match = NA, na_string = "NA") @@ -72,6 +72,8 @@ locating values in the matching column.} \item{digits}{(numeric) the number of digits to use when converting numerical values to characters when determining if values are unique.} +\item{sort}{(logical) sort the values before collapsing.} + \item{priority}{(character) a list of labels in priority order} \item{no_match}{(character, NULL) if !NULL then annotations not matching @@ -162,7 +164,8 @@ M <- combine_records( default_fcn = .unique( digits = 6, separator = ", ", - na_string = "NA" + na_string = "NA", + sort = FALSE ) ) diff --git a/man/filter_records.Rd b/man/filter_records.Rd new file mode 100644 index 0000000..93c60e6 --- /dev/null +++ b/man/filter_records.Rd @@ -0,0 +1,50 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/filter_records_class.R +\name{filter_records} +\alias{filter_records} +\title{Filter rows} +\usage{ +filter_records(where = wherever(A > 0), ...) +} +\arguments{ +\item{where}{(quosures) A list of \code{\link[rlang:quosure-tools]{rlang::quosure}} for evaluation e.g. A>10 willselect all rows where the values in column A are greater than10. A helper function \code{\link{wherever}} is provided to generatea suitable list of quosures. The default is \code{wherever(A > 0)}.} + +\item{...}{Additional slots and values passed to \code{struct_class}.} +} +\value{ +A \code{filter_records} object with the following \code{output} slots: +\tabular{ll}{ +\code{updated} \tab (annotation_source) The updated annotations as an \code{annotation_source} object. \cr +} +} +\description{ +A wrapper around \code{\link[dplyr:filter]{dplyr::filter}}. Select rows from an annotation table using tidy grammar. +} +\details{ +This object makes use of functionality from the following packages:\itemize{ \item{\code{dplyr}} \item{\code{rlang}}} +} +\section{Inheritance}{ + +A \code{filter_records} object inherits the following \code{struct} classes: \cr\cr +\verb{[filter_records]} >> \verb{[model]} >> \verb{[struct_class]} +} + +\examples{ +M = filter_records( + where = wherever(A>10)) + +} +\references{ +Wickham H, François R, Henry L, Müller K, Vaughan D (2023). \emph{dplyr: A +Grammar of Data Manipulation}. R package version 1.1.4, +\url{https://CRAN.R-project.org/package=dplyr}. + +Henry L, Wickham H (2024). \emph{rlang: Functions for Base Types and Core R +and 'Tidyverse' Features}. R package version 1.1.3, +\url{https://CRAN.R-project.org/package=rlang}. +} +\seealso{ +\code{\link[dplyr:filter]{dplyr::filter()}} + +\code{\link[=wherever]{wherever()}} +} diff --git a/man/mwb_compound_lookup.Rd b/man/mwb_compound_lookup.Rd index 99fa7fe..7380f20 100644 --- a/man/mwb_compound_lookup.Rd +++ b/man/mwb_compound_lookup.Rd @@ -55,11 +55,8 @@ M = mwb_compound_lookup( } \references{ -Lloyd GR, Weber RJM (2023). \emph{metabolomicsWorkbenchR: Metabolomics -Workbench in R}. doi:10.18129/B9.bioc.metabolomicsWorkbenchR -\url{https://doi.org/10.18129/B9.bioc.metabolomicsWorkbenchR}, R package -version 1.12.0, -\url{https://bioconductor.org/packages/metabolomicsWorkbenchR}. +Lloyd GR, Weber RJM (????). \emph{metabolomicsWorkbenchR: Metabolomics +Workbench in R}. R package version 1.14.1. Wickham H, François R, Henry L, Müller K, Vaughan D (2023). \emph{dplyr: A Grammar of Data Manipulation}. R package version 1.1.4, diff --git a/man/mwb_structure.Rd b/man/mwb_structure.Rd index af7b1b5..f3a8a93 100644 --- a/man/mwb_structure.Rd +++ b/man/mwb_structure.Rd @@ -47,9 +47,6 @@ Wilke C (2024). \emph{cowplot: Streamlined Plot Theme and Plot Annotations for 'ggplot2'}. R package version 1.1.3, \url{https://CRAN.R-project.org/package=cowplot}. -Lloyd GR, Weber RJM (2023). \emph{metabolomicsWorkbenchR: Metabolomics -Workbench in R}. doi:10.18129/B9.bioc.metabolomicsWorkbenchR -\url{https://doi.org/10.18129/B9.bioc.metabolomicsWorkbenchR}, R package -version 1.12.0, -\url{https://bioconductor.org/packages/metabolomicsWorkbenchR}. +Lloyd GR, Weber RJM (????). \emph{metabolomicsWorkbenchR: Metabolomics +Workbench in R}. R package version 1.14.1. } diff --git a/man/wherever.Rd b/man/wherever.Rd new file mode 100644 index 0000000..3ade13b --- /dev/null +++ b/man/wherever.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/filter_records_class.R +\name{wherever} +\alias{wherever} +\title{Filter helper function to select records} +\usage{ +wherever(...) +} +\arguments{ +\item{...}{Expressions that return a logical value and are defined in terms +of the columns in the annotation_source. If multiple conditions are +included then they are combined with the \code{&} operator. Only records +for which all conditions evaluate to \code{TRUE} are kept.} +} +\value{ +a list of quosures for use with \code{filter_records} +} +\description{ +Returns a list of quosures for use with +\code{filter_records} to allow the use of dplyr-style expressions. See examples. +} +\examples{ +# some annotation data +AN = annotation_source(data = iris) + +# filter to setosa where Sepal length is less than 5 +M = filter_records( + wherever( + Species == 'setosa', + Sepal.Length<5 + ) + ) +M = model_apply(M,AN) +predicted(M) # 20 rows + +} +\seealso{ +\code{\link[=filter_records]{filter_records()}} +}