diff --git a/DESCRIPTION b/DESCRIPTION index 7017688f..30e06abd 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -54,6 +54,7 @@ Collate: 'chartData.R' 'chartDisagg.R' 'chartId.R' + 'chartInclude.R' 'chartInfo.R' 'command.R' 'condaFilepath.R' diff --git a/NAMESPACE b/NAMESPACE index e47e5c9b..08e4a175 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -27,6 +27,7 @@ export(chart) export(chartData) export(chartDisagg) export(chartId) +export(chartInclude) export(chartInfo) export(command) export(condaFilepath) diff --git a/R/chartInclude.R b/R/chartInclude.R new file mode 100644 index 00000000..5bed1d44 --- /dev/null +++ b/R/chartInclude.R @@ -0,0 +1,119 @@ +# Copyright (c) 2024 Apex Resource Management Solution Ltd. (ApexRMS). All rights reserved. +# MIT License +#' @include AAAClassDefinitions.R +NULL + +#' Add or remove values by column in a \code{\link{Chart}} +#' +#' Add or remove values by a specified column in the X or Y axis of a +#' \code{\link{Chart}}. +#' +#' @param chart \code{\link{Chart}} object +#' @param axis character. Either "X" or "Y" corresponding to the X or Y axis of +#' the chart. +#' @param variable character. A variable belonging to the X or Y axis. +#' @param filter character or character vector. A filter column belonging to +#' the X or Y variable.. +#' @param addValue character or character vector. Adds value(s) from the +#' specified filter column and X or Y variable to be included in the chart. +#' @param removeValue character or character vector. Removes value(s) from the +#' specified filter column and X or Y variable from being included in the chart. +#' +#' @return +#' A \code{Chart} object representing a SyncroSim chart +#' +#' @examples +#' \dontrun{ +#' # Create a chart object +#' myChart <- chart(myProject, chart = "New Chart") +#' +#' # Set the chart type and data +#' myChart <- chartData(myChart, y = c("variable1", "variable2"), +#' timesteps = c(0,10), iterationType = "single", iteration = 1) +#' +#' # Include specific values in the chart +#' myChart <- chartInclude(myChart, variable = "variable1", +#' filter="col1", addValue=c("val1", "val2", "val3")) +#' +#' # Remove specific values from the chart +#' myChart <- chartInclude(myChart, variable = "variable1", +#' filter="col1", removeValue="val3") +#' } +#' +#' @export +setGeneric("chartInclude", function(chart, axis, variable, filter, addValue = NULL, + removeValue = NULL) standardGeneric("chartInclude")) + +#' @rdname chartInclude +setMethod("chartInclude", signature(chart = "Chart"), + function(chart, axis, variable, filter, addValue, removeValue) { + + # Set arguments used throughout + chartSession <- .session(chart) + libPath <- .filepath(.ssimLibrary(chart)) + chartCID <- .chartId(chart) + consoleExe <- "SyncroSim.VizConsole.exe" + generalArgs <- list(lib = libPath, cid = chartCID) + + # Validate variable + if (!is.character(variable) && (length(variable) == 1)){ + stop("variable must be a single character.") + } + + # Validate filter + if (!is.character(filter) && (length(filter) == 1)){ + stop("filter must be a single character.") + } + + if (axis == "X"){ + generalArgs <- append(list(`chart-include-x` = NULL), generalArgs) + } else if (axis == "Y"){ + generalArgs <- append(list(`chart-include-y` = NULL), generalArgs) + } else { + stop("axis argument must be 'X' or 'Y'.") + } + + # Include all values specified in addValue argument + if (!is.null(addValue)){ + + if (is.character(addValue)){ + + for (v in addValue){ + + # Convert v to ID values (can provide multiple IDs) + + args <- append(list(set = NULL, var = variable, col = filter), + generalArgs) + tt <- command(args, session = chartSession, program = consoleExe) + + if (tt[1] != "saved"){ + stop(paste("Failed to disaggregate by column", filterCol, ":", tt[1])) + } + } + } else { + stop("addFilter must be a character or vector of characters.") + } + } + + # Remove Y variable disaggregations by filter column provided + if (!is.null(removeFilter)){ + + if (is.character(removeFilter)){ + + for (filterCol in removeFilter){ + args <- append(list(clear = NULL, `chart-disagg-y` = NULL, + var = variable, col = filterCol), generalArgs) + tt <- command(args, session = chartSession, program = consoleExe) + + if (tt[1] != "saved"){ + stop(paste("Failed to remove disaggregate by column", filterCol, + ":", tt[1])) + } + } + } else { + stop("addFilter must be a character or vector of characters.") + } + } + + return(chart) + }) diff --git a/R/chartInfo.R b/R/chartInfo.R index 2a04d503..ab3a9cd0 100644 --- a/R/chartInfo.R +++ b/R/chartInfo.R @@ -12,9 +12,19 @@ NULL #' @param chart character or integer. Either the name or ID of an existing chart. #' If \code{NULL} and a \code{\link{Project}} is provided as the first argument, #' then will return the available variables for charting. +#' @param variable character. The name of a charting variable. If provided, +#' then will return a list of the available filter columns for that variable. +#' Default is \code{NULL}. +#' @param filter character. The name of a filter column for a specified +#' variable. If provided, then will return a list of values that pertain to +#' the specified filter. If the filter column is used to disaggregate the +#' chart data (using the \code{\link{chartDisagg}} function), one panel will be +#' created for each of these values. If you would like to omit values from the +#' chart, you can also add or remove values by the specified filter column +#' using the \code{\link{chartInclude}} function. Default is \code{NULL}. #' #' @return -#' A data.frame of variables, filter columns, and filter values. +#' A data.frame or list of variables, filter columns, and filter values. #' #' @details #' Example arguments: @@ -23,6 +33,10 @@ NULL #' a data.frame of available variables for creating a new chart. #' \item If ssimObject is SyncroSIm Chart or chart is not \code{NULL}: Returns #' a data.frame of variables in use by the specified chart. +#' \item If variable is not \code{NULL}: Returns a list of filter columns +#' that belong to the given variable. +#' \item If variable and filter are not \code{NULL}: Returns a dataframe of +#' value IDs and names that belong to the given variable and filter. #' } #' #' @examples @@ -38,19 +52,29 @@ NULL #' } #' #' @export -setGeneric("chartInfo", function(ssimObject, chart = NULL) standardGeneric("chartInfo")) +setGeneric("chartInfo", function(ssimObject, chart = NULL, variable = NULL, + filter = NULL) standardGeneric("chartInfo")) #' @rdname chartInfo setMethod("chartInfo", signature(ssimObject = "SsimObject"), - function(ssimObject, chart) { + function(ssimObject, chart, variable, filter) { # Set arguments used throughout chartSession <- .session(ssimObject) libPath <- .filepath(.ssimLibrary(ssimObject)) chartPID <- .projectId(ssimObject) consoleExe <- "SyncroSim.VizConsole.exe" + + # Validate variable and filter + if (is.null(variable) && !is.null(filter)){ + stop("Cannot return filter information without a variable.") + } + + returnSingleChart <- (is(ssimObject, "Chart") || !is.null(chart)) && + (is.null(variable)) + returnAllChart <- (is(ssimObject, "Project") || !is.null(variable)) - if (is(ssimObject, "Chart") || !is.null(chart)){ + if (returnSingleChart){ if (is(ssimObject, "Chart")){ chartCID <- .chartId(ssimObject) @@ -63,28 +87,64 @@ setMethod("chartInfo", signature(ssimObject = "SsimObject"), stop("chart argument must be a character or integer.") } + df <- data.frame() + args <- list(list = NULL, `chart-criteria-y` = NULL, lib = libPath, pid = chartPID, cid = chartCID, csv = NULL) yResult <- command(args, session = chartSession, program = consoleExe) yResult <- .dataframeFromSSim(yResult) - yResult$axis <- "y" + + if (nrow(yResult) > 0){ + yResult$axis <- "y" + df <- yResult + } args <- list(list = NULL, `chart-criteria-x` = NULL, lib = libPath, pid = chartPID, cid = chartCID, csv = NULL) xResult <- command(args, session = chartSession, program = consoleExe) xResult <- .dataframeFromSSim(xResult) - xResult$axis <- "x" - missingCol <- setdiff(names(yResult), names(xResult)) - xResult[missingCol] <- "N/A" - df <- rbind(yResult, xResult) + if (nrow(xResult) > 0){ + xResult$axis <- "x" + missingCol <- setdiff(names(yResult), names(xResult)) + xResult[missingCol] <- "N/A" + df <- rbind(df, xResult) + } } - else if (is(ssimObject, "Project")){ + else if (returnAllChart){ args <- list(list = NULL, `chart-variables` = NULL, lib = libPath, pid = chartPID, csv = NULL) df <- command(args, session = chartSession, program = consoleExe) df <- .dataframeFromSSim(df) + + if (!is.null(variable)){ + subsetInfo <- df[df$name == variable,] + + if (is.null(filter)){ + + filters <- strsplit(subsetInfo$filters, split = "|", fixed = TRUE)[[1]] + return(filters) + + } else { + + chartDS <- subsetInfo$datasheet + args <- list(list = NULL, columns = NULL, lib=libPath, allprops = NULL, + sheet = chartDS, csv = NULL) + tt <- command(args, mySession) + df <- .dataframeFromSSim(tt) + df_filtered <- df[df$name %in% filter, ] + + if (nrow(df_filtered) == 0){ + stop(paste("filter argument", filter, "does not exist for variable", variable)) + } + + displayNameDS <- gsub(".*formula1\\^(.+)\\!formula2.*", "\\1", df_filtered$properties) + valuesDS <- .datasheet(myProject, name = displayNameDS, rawValues = T, includeKey = T) + names(valuesDS) <- c("ID", "Name") + return(valuesDS) + } + } } else { diff --git a/R/datasheet.R b/R/datasheet.R index 85df6269..a1bfae03 100644 --- a/R/datasheet.R +++ b/R/datasheet.R @@ -87,6 +87,9 @@ NULL #' @param returnInvisible logical. If \code{TRUE}, returns columns that are #' invisible in the User Interface (i.e., are only used and populated #' internally by SyncroSim or the SyncroSim Package). Default is \code{FALSE} +#' @param rawValues logical. If \code{TRUE}, returns the raw ID values rather +#' than automatically translating the values to strings. Default is +#' \code{FALSE}. #' #' @return #' If \code{summary=TRUE} returns a data.frame of Datasheet names @@ -168,7 +171,7 @@ setGeneric("datasheet", function(ssimObject, name = NULL, project = NULL, scenar sqlStatement = list(select = "SELECT *", groupBy = ""), includeKey = FALSE, forceElements = FALSE, fastQuery = FALSE, returnScenarioInfo = FALSE, - returnInvisible = FALSE) standardGeneric("datasheet")) + returnInvisible = FALSE, rawValues = FALSE) standardGeneric("datasheet")) # Handles case where ssimObject is list of Scenario or Project objects #' @rdname datasheet @@ -177,7 +180,7 @@ setMethod("datasheet", function(ssimObject, name, project, scenario, summary, optional, empty, filterColumn, filterValue, lookupsAsFactors, sqlStatement, includeKey, forceElements, fastQuery, returnScenarioInfo, - returnInvisible) { + returnInvisible, rawValues) { cScn <- ssimObject[[1]] x <- NULL if (is(cScn, "Scenario")) { @@ -202,7 +205,7 @@ setMethod("datasheet", lookupsAsFactors = lookupsAsFactors, sqlStatement = sqlStatement, includeKey = includeKey, forceElements = forceElements, fastQuery = fastQuery, returnScenarioInfo = returnScenarioInfo, - returnInvisible = returnInvisible) + returnInvisible = returnInvisible, rawValues = rawValues) return(out) }) @@ -212,7 +215,8 @@ setMethod("datasheet", signature(ssimObject = "character"), function(ssimObject, name, project, scenario, summary, optional, empty, filterColumn, filterValue, lookupsAsFactors, sqlStatement, - includeKey, fastQuery, returnScenarioInfo, returnInvisible) { + includeKey, fastQuery, returnScenarioInfo, returnInvisible, + rawValues) { return(SyncroSimNotFound(ssimObject)) }) @@ -222,7 +226,7 @@ setMethod("datasheet", function(ssimObject, name, project, scenario, summary, optional, empty, filterColumn, filterValue, lookupsAsFactors, sqlStatement, includeKey, forceElements, fastQuery, returnScenarioInfo, - returnInvisible) { + returnInvisible, rawValues) { temp <- NULL ProjectId <- NULL ScenarioId <- NULL @@ -540,6 +544,11 @@ setMethod("datasheet", args[["filtercol"]] <- filterColumn } + if (rawValues){ + args[["valSheet"]] <- NULL + args <- append(args, list(rawvalues = NULL)) + } + tt <- command(args, .session(x)) if (!identical(tt, "saved")) { diff --git a/man/chartInclude.Rd b/man/chartInclude.Rd new file mode 100644 index 00000000..f8bb86e8 --- /dev/null +++ b/man/chartInclude.Rd @@ -0,0 +1,68 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/chartInclude.R +\name{chartInclude} +\alias{chartInclude} +\alias{chartInclude,Chart-method} +\title{Add or remove values by column in a \code{\link{Chart}}} +\usage{ +chartInclude( + chart, + axis, + variable, + filter, + addValue = NULL, + removeValue = NULL +) + +\S4method{chartInclude}{Chart}( + chart, + axis, + variable, + filter, + addValue = NULL, + removeValue = NULL +) +} +\arguments{ +\item{chart}{\code{\link{Chart}} object} + +\item{axis}{character. Either "X" or "Y" corresponding to the X or Y axis of +the chart.} + +\item{variable}{character. A variable belonging to the X or Y axis.} + +\item{filter}{character or character vector. A filter column belonging to +the X or Y variable..} + +\item{addValue}{character or character vector. Adds value(s) from the +specified filter column and X or Y variable to be included in the chart.} + +\item{removeValue}{character or character vector. Removes value(s) from the +specified filter column and X or Y variable from being included in the chart.} +} +\value{ +A \code{Chart} object representing a SyncroSim chart +} +\description{ +Add or remove values by a specified column in the X or Y axis of a +\code{\link{Chart}}. +} +\examples{ +\dontrun{ +# Create a chart object +myChart <- chart(myProject, chart = "New Chart") + +# Set the chart type and data +myChart <- chartData(myChart, y = c("variable1", "variable2"), +timesteps = c(0,10), iterationType = "single", iteration = 1) + +# Include specific values in the chart +myChart <- chartInclude(myChart, variable = "variable1", +filter="col1", addValue=c("val1", "val2", "val3")) + +# Remove specific values from the chart +myChart <- chartInclude(myChart, variable = "variable1", +filter="col1", removeValue="val3") +} + +}