R/format_digits.R

Defines functions format_digits

Documented in format_digits

# WARNING - Generated by {fusen} from dev/flat_teaching.Rmd: do not edit by hand

#' Format Numeric Columns with Specified Digits
#' 
#' @description
#' The `format_digits` function formats numeric columns in a data frame or data table by rounding numbers to a specified number of decimal places and converting them to character strings. It can optionally format the numbers as percentages.
#'
#' @param data A `data.frame` or `data.table`. The input data containing numeric columns to format.
#' @param cols An optional numeric or character vector specifying the columns to format. If `NULL` (default), all numeric columns are formatted.
#' @param digits A non-negative integer specifying the number of decimal places to use. Defaults to `2`.
#' @param percentage A logical value indicating whether to format the numbers as percentages. If `TRUE`, the numbers are multiplied by 100 and a percent sign (`%`) is appended. Defaults to `FALSE`.
#'
#' @return A `data.table` with the specified numeric columns formatted as character strings with the specified number of decimal places. If `percentage = TRUE`, the numbers are shown as percentages.
#'
#' @details
#' The function performs the following steps:
#' \enumerate{
#'   \item Validates the input parameters, ensuring that `data` is a `data.frame` or `data.table`, `cols` (if provided) are valid column names or indices, and `digits` is a non-negative integer.
#'   \item Converts `data` to a `data.table` if it is not already one.
#'   \item Creates a formatting function based on the `digits` and `percentage` parameters:
#'   \itemize{
#'     \item If `percentage = FALSE`, numbers are rounded to `digits` decimal places.
#'     \item If `percentage = TRUE`, numbers are multiplied by 100, rounded to `digits` decimal places, and a percent sign (`%`) is appended.
#'   }
#'   \item Applies the formatting function to the specified columns:
#'   \itemize{
#'     \item If `cols` is `NULL`, the function formats all numeric columns in `data`.
#'     \item If `cols` is specified, only those columns are formatted.
#'   }
#'   \item Returns a new `data.table` with the formatted columns.
#' }
#'
#' @import data.table
#' @export
#'
#' @note
#' \itemize{
#'   \item The input `data` must be a `data.frame` or `data.table`.
#'   \item If `cols` is specified, it must be a vector of valid column names or indices present in `data`.
#'   \item The `digits` parameter must be a single non-negative integer.
#'   \item The original `data` is not modified; a modified copy is returned.
#' }
#' @examples
#' # Example: Number formatting demonstrations
#'
#' # Setup test data
#' dt <- data.table::data.table(
#'   a = c(0.1234, 0.5678),      # Numeric column 1
#'   b = c(0.2345, 0.6789),      # Numeric column 2
#'   c = c("text1", "text2")     # Text column
#' )
#'
#' # Example 1: Format all numeric columns
#' format_digits(
#'   dt,                         # Input data table
#'   digits = 2                  # Round to 2 decimal places
#' )
#'
#' # Example 2: Format specific column as percentage
#' format_digits(
#'   dt,                         # Input data table
#'   cols = c("a"),              # Only format column 'a'
#'   digits = 2,                 # Round to 2 decimal places
#'   percentage = TRUE           # Convert to percentage
#' )
format_digits <- function(data, cols = NULL, digits = 2, percentage = FALSE) {
  # Parameter checks
  if (!is.data.frame(data)) {
    stop("Input data must be a data.frame or data.table object")
  }

  # Convert to data.table if it's a data.frame
  if (!is.data.table(data)) {
    data <- as.data.table(data)
  }

  # Check cols parameter
  if (!is.null(cols)) {
    if (!is.numeric(cols) && !is.character(cols)) {
      stop("'cols' must be numeric or character vector")
    }

    if (length(cols) == 0) {
      stop("When specified, 'cols' cannot be empty")
    }

    if (is.numeric(cols)) {
      if (any(cols < 1) || any(cols > ncol(data))) {
        stop("Numeric column indices must be between 1 and ", ncol(data))
      }
      cols <- names(data)[cols]
    }

    if (!all(cols %in% names(data))) {
      invalid_cols <- cols[!cols %in% names(data)]
      stop("Following columns do not exist in the data: ",
           paste(invalid_cols, collapse = ", "))
    }
  }

  # Check digits parameter
  if (!is.numeric(digits) ||
      length(digits) != 1 ||
      digits < 0 ||
      digits != round(digits)) {
    stop("'digits' must be a single non-negative integer")
  }

  # Create format string based on percentage parameter
  fmt <- if(percentage) {
    function(x) sprintf(paste0("%.", digits, "f%%"), round(as.numeric(x) * 100, digits))
  } else {
    function(x) sprintf(paste0("%.", digits, "f"), as.numeric(x))
  }

  # Create a copy of the data to modify
  result <- copy(data)

  # Process all numeric columns if cols is NULL
  if (is.null(cols)) {
    result[, names(.SD) := lapply(.SD, fmt), .SDcols = is.numeric][]
  } else {
    # Process specified columns
    result[, (cols) := lapply(.SD, fmt), .SDcols = cols][]
  }

  return(result)
}

Try the mintyr package in your browser

Any scripts or data that you put into this service are public.

mintyr documentation built on April 4, 2025, 2:56 a.m.