Indrajeet Patil
Indrajeet Patil

Reputation: 4889

printing tibble to console with a message

How can I print a tibble to the console along with a message? I want to write a function which outputs a tibble along with a verbose message that contains some information about the nature of that tibble.

Here is a highly simplistic example of what I have in mind. In the first attempt, the function doesn't work. In the second attempt, it works but outputs some other unnecessary details.

# libraries needed
library(crayon)
library(tibble)

# writing the function
try.fn1 <- function() {
  # prepare the tibble
  x <- tibble::as.tibble(x = rnorm(1:10))
  # output the associated message to the user of the function
  base::message(
    cat(crayon::blue("The tibble I prepared is-"), x)
    )
  base::message(print(x))
}

# using the function
try.fn1()
#> The tibble I prepared is-
#> Error in cat(crayon::blue("The tibble I prepared is-"), x): argument 2 (type 'list') cannot be handled by 'cat'

# another attempt
try.fn2 <- function() {
  # prepare the tibble
  x <- tibble::as.tibble(x = rnorm(1:10))
  # output the associated message to the user of the function
  base::message(
    cat(crayon::blue("The tibble I prepared is-"))
  )
  base::message(print(x))
}

# using the function
try.fn2()
#> The tibble I prepared is-
#> 
#> # A tibble: 10 x 1
#>       value
#>       <dbl>
#>  1 -0.00529
#>  2  0.562  
#>  3 -0.511  
#>  4 -0.260  
#>  5 -0.232  
#>  6 -1.92   
#>  7 -0.698  
#>  8  2.38   
#>  9  1.59   
#> 10 -0.585
#> c(-0.00528727617885923, 0.56168758575177, -0.510982641120654, -0.260458372988822, -0.231847890601322, -1.91514178853023, -0.697661618989503, 2.37722341810185, 1.5869372625472, -0.584576993642516)

Created on 2018-03-15 by the reprex package (v0.2.0).

Upvotes: 3

Views: 1826

Answers (2)

r2evans
r2evans

Reputation: 161110

I suggest you either use or mimic the code within the unexported print functions from tibble. To access unexported functions, use triple-colons to access tibble:::print.tbl_df (and .tbl).

Two things to know to know to look for these functions:

  1. Many functions in R have different behaviors (even different arguments) based on the object(s) called in them. For instance, summary behaves differently if given an lm object, a matrix, etc. To see all of the differentsummaryfunctions, trymethods(summary)`. (A good reference for learning more about this, called "S3", can be seen in Hadley's Advanced R online book.)

    If you bring this around to this question, running methods("print") presents (among others):

    m <- methods("print")
    m[ grepl("tbl|frame",m) ]
    # [1] "print.data.frame" "print.frame"      "print.tbl_cube"   "print.tbl_df"    
    # [5] "print.tbl_lazy"   "print.tbl_sql"   
    

    These don't have to be exported by their respective packages to be made available to R. In fact, I seem to find more of them unexported. The fact that print(my_new_object) just simply works can be a huge convenience to users new and experienced.

  2. You can always find the source for this function online (such as on GitHub, like this source here), but this is not always convenient, and if you aren't careful, it could be for a version of the package other than what you have installed.

    Most objects in R can be inspected (deeply or otherwise) just by typing the name on the console. This works just as well for variables as it does for functions. There are three ways to look at functions:

    1. After library(pkgname) or require(pkgname), just type the function name. This is how most people learn and interact with R.

    2. Even before loading a package with library or require, you can view any package's functions with double-colons, for example dplyr::filter. This is also useful when a function name is shared between packages (possible "masking" or collisions), and you want to be clear which one to use.

    3. If a function is not exported, no matter if you've called library or not, you can only access it with the triple-colons, such as tibble:::print.tbl_df. (Actually, there are ways to view the source without the colons such as in R's browser, but that's not important here.)

There is a risk with using unexported functions. They are typically unexported for one of several reasons, including most importantly (a) not central to the function of the package, and (b) the author has no need or intention of maintaining that function's API (arguments, output) between releases. It is possible (and happens frequently) that an unexported function may disappear, change arguments dramatically, or change methods. Essentially an author has invested in maintaining some semblance of connsistency on exported functions, but not the unexported ones.

So by suggesting you look at or use tibble:::print.tbl_df, there's risk: it is possible that they will change or remove that function. Having said that, the print.* functions are often unexported because they are intended to only be used using the generic S3 version, print. The only reason I would expect this specific function to change is if the authors changed the spelling or type of objects the package uses. And I don't see that happening any time soon.

Upvotes: 4

HenrikB
HenrikB

Reputation: 6815

Capture standard output, which is where cat() and print() send output, then concatenate and pass to message:

message(paste(capture.output({
  cat(crayon::blue("The tibble I prepared is-\n"))
  print(x)
}), collapse = "\n"))

Upvotes: 1

Related Questions