如何使用print或cat缩进多行输出(如summary)的输出,并保持列对齐?

如何使用print或cat缩进多行输出(如summary)的输出,并保持列对齐?,r,printing,indentation,cat,summary,R,Printing,Indentation,Cat,Summary,这个问题可能推广到打印任何类型的多行输出,并保持列对齐。我的实际问题与summary.default的输出有关 我试图在summary.default函数的cat输出中添加二的倍数缩进。我曾尝试使用cat和print,也参考了一些相关的答案,但都失败了 f <- function(x) { s <- summary.default(x) liner <- Reduce(paste0, rep("-", 70)) cat("\n"

这个问题可能推广到打印任何类型的多行输出,并保持列对齐。我的实际问题与
summary.default的输出有关

我试图在
summary.default
函数的
cat
输出中添加二的倍数缩进。我曾尝试使用
cat
print
,也参考了一些相关的答案,但都失败了

f <- function(x) {
  s <- summary.default(x)
  liner <- Reduce(paste0, rep("-", 70))
  cat("\n", liner, "\n")  ## ATT 1. -------------------------------
  cat("\n", "foo first attempt", "\n")
  cat("\n--|\n")
  
  print(round(s, 3))  #
  
  cat("\n----|\n")
  cat("\n    *additional information\n")
  cat("\n", liner, "\n")  ## ATT 2. -------------------------------
  cat("\n", "foo second attempt", "\n")
  cat("\n--|\n")
  
  print(unname(as.data.frame(cbind("   ", t(attr(s, "names"))))), row.names=F)  #
  print(unname(as.data.frame(cbind(" ", t(round(unclass(s), 3))))), row.names=F)  #
  
  cat("\n----|\n")
  cat("\n    *additional information\n")
  cat("\n", liner, "\n")  ## ATT 3. -------------------------------
  cat("\n", "foo third attempt", "\n")
  cat("\n--|\n")
  cat("\n  ", attr(s, "names"), "\n")
  
  cat("\n  ", round(s, 3), "\n")  #
  
  cat("\n----|\n")
  cat("\n    *additional information\n")
}

我唯一能想到的是手动重新组合“摘要”输出,以考虑不同的“单元格”宽度:

add_indent_and_right_align <- function(summry, indent=2, minDist= 2, rounding = 3) {
  # add an indent and then right-align summary output table
  #
  # summry - summary object
  # indent - integer Number of spaces to add before summary output
  # minDist . integer Minimal number of spaces between two columns
  # rounding - integer Number of decimals to round summary to

  header <- attr(summry, "names")
  value <- round(summry, 3)     
  r = list()
  for (i in seq_along(header)) {
    # find out how wide the column has to be
    # to fit header and value and indent (if first column) or minDist
    #
    max_len <- max(nchar(header[i]), nchar(value[i]))       
    if (i == 1) {
      cell_width <- max_len + indent
      r[1] <- paste0(paste0(rep(" ", cell_width - nchar(header[i])), collapse=""), header[i])
      r[2] <- paste0(paste0(rep(" ", cell_width - nchar(value[i])), collapse=""), value[i])
    } else {
      cell_width <- max_len + minDist
      r[1] <- paste0(r[1], paste0(rep(" ", cell_width - nchar(header[i])), collapse=""), header[i])
      r[2] <- paste0(r[2], paste0(rep(" ", cell_width - nchar(value[i])), collapse=""), value[i])
    }
  }
  return(paste0(r, collapse="\n"))
}

f <- function(x) {
  indent <- 4 # how many spaces shoud the whole summary output be indented?
  s <- summary.default(x)

  cat(paste0(rep("-", 70), collapse=""), "\n")
  cat("\n")
  cat("foo some text", "\n")
  cat("\n")
  cat(add_indent_and_right_align(summry=s, indent=4, minDist= 1, rounding = 3), "\n")
  cat("\n")
  cat(paste0(paste0(rep(" ", indent), collapse=""), "*additional information"), "\n")
  cat("\n")
}

set.seed(1)
x <- rnorm(100)
f(x)

对于此任务,您可以连续使用两个基r函数。有一个函数
capture.output
,它可以捕获像print这样的命令的输出。使用
paste
组合所需的空格数,可以使用
writelines
将其写入标准输出,从而保留数据帧打印输出的行结构。 要执行上述操作,请将打印输出中给出的所有信息合并为data.frame(df)示例


我添加了roe.names=F,以禁止打印数据帧的行号

Nice hack,谢谢!不过,我选择了另一个答案,因为这似乎是一种标准的方式。太棒了
writeLines(粘贴0(“,capture.output(print(s,row.names=F))
最终适用于我的特殊情况。
---------------------------------------------------------------------- 
  
foo some text 

    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  -2.069  -0.654  -0.092  -0.075   0.696   1.997 
      
    *additional information
add_indent_and_right_align <- function(summry, indent=2, minDist= 2, rounding = 3) {
  # add an indent and then right-align summary output table
  #
  # summry - summary object
  # indent - integer Number of spaces to add before summary output
  # minDist . integer Minimal number of spaces between two columns
  # rounding - integer Number of decimals to round summary to

  header <- attr(summry, "names")
  value <- round(summry, 3)     
  r = list()
  for (i in seq_along(header)) {
    # find out how wide the column has to be
    # to fit header and value and indent (if first column) or minDist
    #
    max_len <- max(nchar(header[i]), nchar(value[i]))       
    if (i == 1) {
      cell_width <- max_len + indent
      r[1] <- paste0(paste0(rep(" ", cell_width - nchar(header[i])), collapse=""), header[i])
      r[2] <- paste0(paste0(rep(" ", cell_width - nchar(value[i])), collapse=""), value[i])
    } else {
      cell_width <- max_len + minDist
      r[1] <- paste0(r[1], paste0(rep(" ", cell_width - nchar(header[i])), collapse=""), header[i])
      r[2] <- paste0(r[2], paste0(rep(" ", cell_width - nchar(value[i])), collapse=""), value[i])
    }
  }
  return(paste0(r, collapse="\n"))
}

f <- function(x) {
  indent <- 4 # how many spaces shoud the whole summary output be indented?
  s <- summary.default(x)

  cat(paste0(rep("-", 70), collapse=""), "\n")
  cat("\n")
  cat("foo some text", "\n")
  cat("\n")
  cat(add_indent_and_right_align(summry=s, indent=4, minDist= 1, rounding = 3), "\n")
  cat("\n")
  cat(paste0(paste0(rep(" ", indent), collapse=""), "*additional information"), "\n")
  cat("\n")
}

set.seed(1)
x <- rnorm(100)
f(x)
---------------------------------------------------------------------- 

foo some text

    Min. 1st Qu. Median  Mean 3rd Qu.  Max.
  -2.215  -0.494  0.114 0.109   0.692 2.402

  *additional information
df = data.frame("Min."=-2.069, "First Qu."= -0.654,  "Median"= -0.092   , "Mean"  =-0.075, "Third Qu."=  0.696,    "Max."=  1.997 )
writeLines(paste0("  ", capture.output(print(df, row.names = F))))