Defines functions make.table

Documented in make.table

#' Make a table from HexSimR results
#' \code{make.table} reads the result files generated by HexSimR and compiles a 
#' table after having rounded the decimal digits.
#' \code{make.table} can process either descriptive statistics (generated using 
#' \code{collate.census}, \code{ranges} or \code{move}) or statistical 
#' comparisons generated using \code{SSMD.census}, \code{SSMD.ranges} or 
#' \code{SSMD.move}), but only one type of result in any one time. For each run 
#' of \code{make.table} a sheet is created as output in a .xls file. If the name
#' of the xls file is kept equal, the new sheet is added to the existing file.
#' \strong{ATTENTION:} If the name of the new sheet is the same of an existing
#' one, the data will be pasted over in the existing sheet, possibly making the
#' results incomprehensible.
#' When processing census data, several files can be passed at once by passing a
#' character vector of length > 1 to \code{fnames}. Note that the extension 
#' (.csv) of the file is used to identify whether it was requested to process 
#' descriptive statistics generated by movement reports. If you have changed the
#' extensions of the result files, this function may have impredictable results.
#' When more than one scenario is processed, then \code{make.table} assumes 
#' that, within each scenario, the result file name is the same. The only 
#' exception is when processing the descriptive statistics of census data. In 
#' this case, the name of scenario is automatically added to the suffix. In 
#' these cases, the suffix of the files has to be passed to \code{fnames} (i.e. 
#' \emph{"[ncensus].all.xlsx"}, where \emph{"ncensus"} is the number of the 
#' census event, and \emph{".all.xlsx"} is the standard suffix that HexSimR adds
#' to all files generated with \code{collate.census}.
#' \code{colh} is used to pass the headings of the columns to be processed. It 
#' \strong{MUST} be passed as a list, with an element for each file that was 
#' passed with \code{fnames}.
#' If \code{SSMD=TRUE} and \code{scenarios="all"}, R may throw an error because 
#' the base scenario is included in \code{scenarios} (unless it was manually 
#' removed) but it is not present in the result file. When \code{SSMD=TRUE} a
#' character vector has to be passed to \code{scenarios}.
#' When \code{SSMD=TRUE}, currently, only p-values are reported in the table.
#' Note that when \code{SSMD=TRUE}, and the function is pointed to a SSMD 
#' comparison of ranges report statistics, the appropriate setting for the time
#' step is \code{time.steps=NULL} (default) because these are already subsetted
#' when the SSMD comparison is done, unless all time steps were kept when calling 
#' \code{ranges} or \code{multi.reports}. Also, unless issue #3 has been resolved,
#' the argument  \code{time.steps} only works correctly if all time steps were 
#' logged.
#' By default, the sheet in the xls file takes name "Descriptive" or "SSMD", 
#' depending on whether \code{SSMD=FALSE} or \code{SSMD=TRUE} respectively. This
#' behaviour can be altered by passing a character vector to \code{tab.name}.
#' @param fnames The name(s) of the output file(s) to be processed. If more the 
#'   one scenario is passed, the output file names have to be all equal
#' @param time.steps A numeric vector with the time steps to include. If NULL
#'   (default), all time steps are included. See details for more information
#' @param SSMD Whether the data being processed are SSMD comparisons (default:
#'   FALSE)
#' @param colh A list with as many elements as the length of fnames. Each 
#'   element is a character vector with the names of the column headings to be 
#'   considered for the relative fnames (default: ranges' headings)
#' @param vround The number of digits the variable (e.g. the mean, the p-values)
#'   should be rounded to
#' @param sdround If SSMD=FALSE, the number of digits the standard deviation 
#'   should be rounded to
#' @param table.name The name of the file where to save the table
#' @param tab.name The name of the tab to be saved in the xls file. By default, 
#'   "Descriptive" or "SSMD", depending on whether \code{SSMD=FALSE} or 
#'   \code{SSMD=TRUE} respectively.
#' @param save2disk Whether to save to disk the table
#' @param dir.out The directory where to save the table. If NULL (default), the 
#'   file will be written in the 'Results' folder
#' @inheritParams collate.census
#' @seealso \code{\link{collate.census}}, \code{\link{ranges}}, 
#'   \code{\link{move}}, \code{\link{SSMD.census}}, \code{\link{SSMD.ranges}}, 
#'   \code{\link{SSMD.move}}
#' @import XLConnect
#' @import data.table
#' @return A data.frame (data.table) with the compiled table. If save2disk=TRUE 
#'   an xls file is also saved to disk.
#' @export
make.table <- function(path.results=NULL, scenarios="all", fnames, SSMD=FALSE, 
                colh=list(c("GroupSize", "Resources",	"nGroups", "ha", "sqkm")), 
                vround=1, sdround=1, time.steps=NULL, table.name="Tables.xlsx", 
                tab.name=NULL, save2disk=TRUE, 
                dir.out=NULL) {
  # Helper functions
  combine <- function(i, data_r, data_sd_r) {
    comb <- paste0(data_r[[i]], " (", data_sd_r[[paste0(i, "_sd")]], ")")
  read_res <- function(scenario, path.results, fname, SSMD, time.steps, colh, vround, 
                        sdround, dir.out) {
    nC_fname <- nchar(fname)
    ext <- substr(fname, nC_fname - 3, nC_fname)
    if(SSMD == FALSE & ext == ".csv") {
      tab <- fread(paste(path.results, scenario, fname, sep="/"))
      setkey(tab, V1)
      data <- tab["Mean", colh, with=FALSE]
      data_sd <- tab["Std", colh, with=FALSE]
      sds <- paste0(colh, "_sd")
      setnames(data_sd, sds)
      data <- cbind(data, data_sd)
      colh <- make.names(colh)
      sds <- make.names(sds)
      setnames(data, c(colh, sds))
    } else {
      if(substr(fname, nC_fname - 7, nC_fname) == "all.xlsx") {
        fname <- paste(scenario, fname, sep=".") 
      wb <- loadWorkbook(paste(path.results, 
                               if(SSMD == FALSE) scenario, 
      if(SSMD == FALSE) {
        tab <- data.table(readWorksheet(wb, sheet="means"))
      } else {
        if(nchar(scenario) > 25) {
          scen_short <- substr(scenario, nchar(scenario) - 24, nchar(scenario)) 
        } else {
          scen_short <- scenario
        tab <- data.table(readWorksheet(wb, sheet=paste0("pval_", scen_short)))
      if(is.null(time.steps)) {
        data <- tab[, colh, with=FALSE]
      } else {
        data <- tab[(time.steps + 1), colh, with=FALSE]
      if(SSMD == FALSE) {
        tab <- data.table(readWorksheet(wb, sheet="sd"))
        if(is.null(time.steps)) {
          data_sd <- tab[, colh, with=FALSE]
        } else {
          data_sd <- tab[(time.steps + 1), colh, with=FALSE]
        sds <- paste0(colh, "_sd")
        setnames(data_sd, sds)
        data <- cbind(data, data_sd)
    data_r <- data[, lapply(.SD, round, vround), .SDcols=colh]
    if(SSMD == FALSE) {
      data_r[, (colh) := lapply(colh, 
                                combine, data_r,
                                data[, lapply(.SD, round, sdround), .SDcols=sds])]

    data_r[, Scenario := scenario]
    if(!is.null(time.steps))  data_r[, TimeStep := time.steps]
    setcolorder(data_r, c("Scenario", if(!is.null(time.steps)) "TimeStep",  colh))
  txt <- "Please, select the 'Results' folder within the workspace"
  if(is.null(path.results)) path.results <- tk_choose.dir(caption = txt)
  suppressWarnings(if(scenarios == "all") 
    scenarios <- list.dirs(path=path.results, full.names=FALSE, recursive=FALSE))
  if(is.null(tab.name)) {
    if(SSMD) tab.name <- "SSMD" else tab.name <- "descriptive"

  ldat <- list()
  i <- 0
  for(fname in fnames) {
    i <- i + 1
    ldat[[i]] <- lapply(scenarios, read_res, path.results, fname=fname, SSMD, 
                        time.steps, colh[[i]], vround, sdround, dir.out)
    ldat[[i]] <- rbindlist(ldat[[i]], use.names=T)
  data <- do.call(cbind, ldat)
  scen_inst <- grep("Scenario", names(data))
  if(length(scen_inst) > 1) {
    data[, scen_inst[2:length(scen_inst)] := NULL, with=FALSE]
  time_inst <- grep("TimeStep", names(data))
  if(length(time_inst) > 1) {
    data[, time_inst[2:length(time_inst)] := NULL, with=FALSE]
  if(save2disk == TRUE) {
    dir.create(paste(path.results, dir.out, sep="/"), showWarnings=FALSE, 
    wb <- loadWorkbook(paste(path.results, dir.out, table.name, sep="/"), 
    createSheet(wb, name=tab.name)
    writeWorksheet(wb, data, sheet=tab.name)
carlopacioni/HexSimR documentation built on Nov. 11, 2018, 8:33 p.m.