6 Methods (part 2)
6.1 Introduction
In this chapter you will learn how to create common S3 class methods such as print()
, summary()
, and plot()
.
6.2 Print Method
Until now we have a toss()
function that produces objects of the homonym class "toss"
. Right now this type of output is basically a list. For instance, consider a Mexican peso with two sides: aguila
and sol
. And let’s use toss()
to flip a peso 15 times.

Figure 6.1: An old Mexican peso (www.coinfactswiki.com)
By the way, flips are commonly referred to as volados in Mexico:
set.seed(789)
peso <- coin(c('aguila', 'sol'))
volados <- toss(peso, 15)
volados
#> $coin
#> object "coin"
#>
#> side prob
#> 1 aguila 0.5
#> 2 sol 0.5
#>
#> $tosses
#> [1] "aguila" "sol" "sol" "aguila" "sol" "sol" "aguila"
#> [8] "sol" "sol" "sol" "sol" "aguila" "sol" "sol"
#> [15] "sol"
#>
#> $total
#> [1] 15
#>
#> $heads
#> [1] 4
#>
#> $tails
#> [1] 11
#>
#> attr(,"class")
#> [1] "toss"
Every time you type in the name of an object "toss"
, like volados
in the previous example, the output is displayed like any other list. R displays the values of $coin
and its attributes (attr
), the $tosses
, the $total
, the number of $heads
and $tails
, and finally the class attribute.
Instead of displaying all the elements that are in the output list returned by toss()
, it would be more convenient to display information in a more compact way, for instance some sort of text containing the following bullets:
- object “toss”
- coin: “aguila”, “sol”
- total tosses: 15
- num of aguila: 11
- num of sol: 4
Typically, most classes in R have a dedicated printing method. Depending on the type of object, the default printed information may consist of a couple of lines, or sometimes a very verbose output. To create such
a method we use the generic function print()
. To be more precise, we declare a new print method for objects of class "toss"
like so:
# print method for object of class "toss"
print.toss <- function(x, ...) {
cat('object "toss"\n')
cat(sprintf('sides: "%s", "%s"', x$coin$sides[1], x$coin$sides[2]), "\n")
cat(sprintf('prob: "%s", "%s"', x$coin$prob[1], x$coin$prob[2]), "\n")
cat("total tosses:", x$total, "\n")
cat(sprintf("num of %s:", x$coin$sides[1]), x$heads, "\n")
cat(sprintf("num of %s:", x$coin$sides[2]), x$tails, "\n")
invisible(x)
}
By convention, print
methods return the value of their principal argument invisibly. The invisible
function turns off automatic printing, thus preventing an infinite recursion when printing is done implicitly at the session level.
After a print
method has been defined for an object "toss"
, everytime you type an object of such class, R will search for the corresponding method and display the output accordingly:
# testing print method
set.seed(789)
volados <- toss(peso, 15)
volados
#> object "toss"
#> sides: "aguila", "sol"
#> prob: "0.5", "0.5"
#> total tosses: 15
#> num of aguila: 4
#> num of sol: 11
Here’s another example with the quarter1
coin used in previous chapters:
6.3 Summary Method
For most purposes the standard print
method will be sufficient output. However, sometimes a more extensive display is required. This can be done with a summary
function. To define this type of method we use the function summary()
.
The way you declare a summary
method is similar to the way you declare a print
method. You need to specify summary.toss
, indicating that there will be a new summary method for objects of class "toss"
. The summary
will return an object of class "summary.toss"
, which is typically a list (although you can return any other type of data object).
Here’s the summary.toss()
function:
summary.toss <- function(x, ...) {
proportions <- c(
sum(x$tosses == x$coin$sides[1]) / x$total,
sum(x$tosses == x$coin$sides[2]) / x$total
)
freqs <- data.frame(
side = x$coin$sides,
count = c(x$heads, x$tails),
prop = proportions)
obj <- list(freqs = freqs)
class(obj) <- "summary.toss"
obj
}
Let’s test it:
summary(quarter_flips)
#> $freqs
#> side count prop
#> 1 washington 20 0.4
#> 2 bald-eagle 30 0.6
#>
#> attr(,"class")
#> [1] "summary.toss"
When implementing summary
methods for specific classes, there’s actually one more method that you typically have to create: a sibling print.summary
method. The reason why you need these pair of methods is because an object "summary.toss"
—returned by summary()
—will very likely need its own print
method, thus requiring a print.summary.toss()
function.
Let’s test it:
summary(quarter_flips)
#> summary "toss"
#>
#> side count prop
#> 1 washington 20 0.4
#> 2 bald-eagle 30 0.6
You can actually store the output of summary()
and inspect its contents:
6.4 Plot Method
We can also define a plot
method for objects of class "toss"
:
What we want to plot of an object "toss"
is the series of realtive frequencies (of either "heads"
ot "tails"
). This means we need to create a couple of auxiliary functions:
head_freqs <- function(x) {
cumsum(x$tosses == x$coin$sides[1]) / 1:x$total
}
tail_freqs <- function(x) {
cumsum(x$tosses == x$coin$sides[2]) / 1:x$total
}
frequencies <- function(x, side = 1) {
if (side == 1) {
return(head_freqs(x))
} else {
return(tail_freqs(x))
}
}
Here’s one way to define a plot()
method for "toss"
objects:
plot.toss <- function(x, side = 1, ...) {
freqs <- frequencies(x, side = side)
plot(1:x$total, freqs, type = "n", ylim = c(0, 1), las = 1,
xlab = "number of tosses", bty = "n",
ylab = sprintf("relative frequency of %s", x$coin$sides[side]))
abline(h = 0.5, col = "gray70", lwd = 1.5)
lines(1:x$total, freqs, col = "tomato", lwd = 2)
title(sprintf("Relative Frequencies in a series of %s coin tosses", x$total))
}
Let’s test our plot
method:
Make a donation
If you find this resource useful, please consider making a one-time donation in any amount. Your support really matters.