5

I've been working on quite an ambitious function, which I hope can be used by people other than me once I am finished. When it's just me using the function I can live with the output being kind of lame, but what if I want some nice looking output? What I'm looking for is essentially this:

  • A way of printing something readable to the console
  • Being able to access what's printed

More specifically, let's assume I have three scalar objects I want to be printed: stat, dfree and pval. Currently, the way I do it is:

result <- list(statistic = stat, degrees = dfree, p.value = pval)
return(result)

That way I can access these values by running, for example (the function is called whites.htest):

whites.htest$p.value

It works, but the output is kind of ugly.

> whites.htest(var.modell)
$statistic
[1] 36.47768

$degrees
[1] 30

$p.value
[1] 0.1928523

If we run a simple VAR model like this:

> library(vars)
> data <- matrix(rnorm(200), ncol = 2)
> VAR(data, p = 2, type = "trend")

VAR Estimation Results:
======================= 

Estimated coefficients for equation y1: 
======================================= 
Call:
y1 = y1.l1 + y2.l1 + y1.l2 + y2.l2 + trend 

       y1.l1        y2.l1        y1.l2        y2.l2        trend 
-0.090102007 -0.060138062  0.126250484  0.014423006  0.003138521 


Estimated coefficients for equation y2: 
======================================= 
Call:
y2 = y1.l1 + y2.l1 + y1.l2 + y2.l2 + trend 

       y1.l1        y2.l1        y1.l2        y2.l2        trend 
 0.040118527  0.018274399 -0.132943318 -0.031235939  0.003242241

The output looks really good. I've had a look at the underlying code for it (by simply running VAR), but I cannot find what makes it look good like this.

So my question is, how do I print something nice and readable to the console while still being able to access individual objects (i.e. results) from the function?

hejseb
  • 2,064
  • 3
  • 18
  • 28
  • I don't see what's ugly about your output. You're comparing two completely different things, If you give an example of what you really need your output to be, with sample data included, you'll probably get better answers. – N8TRO Feb 23 '13 at 23:05

4 Answers4

7

One way I could think of to prettify the input (and gain more control if you're writing more functions) is to create a class and modify the show method.. Something like this:

# set your class name and its representation is list here.
setClass( "stat_test", representation("list"))


# show method (here's how the output would be printed
# you can format to whatever you want... to show and how to show
setMethod("show", "stat_test", function(object) {
    cat("object of", class(object), "\n")
    cat("Estimated Coefficients\n")
    cat("  statistics\t\t\tdegrees\t\t\tp.value\n")
    cat("  ", object$statistics, "\t\t\t", object$degrees, "\t\t\t", object$p.value,"\n")
})


# now your actual function (here dummy of course)
my_fun <- function(x) {
    t <- list(statistics=1.5, degrees=30, p.value=1e-2)
    new("stat_test", t)
}

# now calling
w <- my_fun(2)
> w # you get

object of stat_test 
Estimated Coefficients
  statistics            degrees         p.value
  1.5            30              0.01 

You should take care of the alignments of course. But this is one basic idea.

Arun
  • 116,683
  • 26
  • 284
  • 387
  • 1
    Terrific! Thanks a lot, that's a perfect basic code to start off from and then expand. Brilliant :) – hejseb Feb 23 '13 at 23:24
4

You should give your result a class, say "resclass" and create a print.resclass function. print is a generic function an will search the function space for print.resclass and apply it to your object. You can either have the print method return NULL or have it return the object value invisibly. The usual way of doing this is repeated calls to cat. I see Arun has already provided an example. It's always possible to learn from you package authors. Here's the print.varest function that you admired:

 vars:::print.varest
#---------------
function (x, digits = max(3, getOption("digits") - 3), ...) 
{
    dim <- length(x$varresult)
    names <- colnames(x$y)
    text1 <- "VAR Estimation Results:"
    cat(paste("\n", text1, "\n", sep = ""))
    row <- paste(rep("=", nchar(text1)), collapse = "")
    cat(row, "\n")
    cat("\n")
    for (i in 1:dim) {
        result <- coef(x$varresult[[i]])
        text1 <- paste("Estimated coefficients for equation ", 
            names[i], ":", sep = "")
        cat(text1, "\n")
        row <- paste(rep("=", nchar(text1)), collapse = "")
        cat(row, "\n")
        text2 <- paste("Call:\n", names[i], " = ", paste(names(result), 
            collapse = " + "), sep = "")
        cat(text2, "\n\n")
        print(result, ...)
        cat("\n\n")
    }
    invisible(x)
}
<environment: namespace:vars>
IRTFM
  • 258,963
  • 21
  • 364
  • 487
1

adding to @DWin's answer..

# run your example code
library(vars)
data <- matrix(rnorm(200), ncol = 2)
# store the output of `x`
x <- VAR(data, p = 2, type = "trend")

# what kind of object is `x`?
class( x )

# look at code that the author of the `vars`
# package wrote for the print method
getS3method( 'print' , 'varest' )

# look at others..
getS3method( 'print' , 'varsum' )

# ..and others
methods( 'print' )
Anthony Damico
  • 5,779
  • 7
  • 46
  • 77
  • Nice, that explains some (especially now that I can actually view how the output for varest is created!). A silly question, perhaps, but how do I create a print method for my new class (say "resclass")? Say I want it to print "This is the p-value: <>" using this way of doing that rather than simply print(paste("This is the p-value: ", pval, sep="")). How would I do that? – hejseb Feb 23 '13 at 23:19
1

The usual practice is to assign the return value from your function to have a given class (you choose the name of the class), then you create a print method for the class which will nicely format the output (often using cat) and return the same object invisibly. Often there is also a summary method and a print.summary method to give additional output.

Other things to help with nice, but easy, output is to put the things that you want on the screen in a matrix and give the matrix row names and column names, then print the matrix and the print.matrix function will take care of lining things up nicely. Some functions will combine using cat and printing matrices.

Greg Snow
  • 48,497
  • 6
  • 83
  • 110