21 R navigation tools

17 Aug 2014
2014/08/17

Navigation gets you from where you are to where you want to be.

Speaking of navigation, you can jump to selected sections of this post: Navigation; R-bloggers; Task views; Rdocumentation.org; sos package; ??; apropos; ls; methods; getAnywhere; :::; find; args; grep; %in%; str; getwd; file.choose; Spyglass summary; browser; See also.

Overview

Figure 1: A map of the R world. Rmap Each R session has a workspace specific to it. Ironically this is called the global environment.  You can see what objects are in it with the command:

ls()

Or if you prefer explicitness over laziness:

objects()

But your R session will know about other objects as well. Those objects will be in items that are on the search list.  You can see the current state of the search list with:

search()

The items can be packages, or files of R objects (created, for example, via the save function and put on the search list with attach).  It is almost a true statement that R searches for objects in the order of the search list — first in the global environment, then in whatever is second on the search list, and so on.

The packages on the search list will have been selected from the library of packages on your machine.  You see what packages are in your library with:

library()

Add a package to the search list with the require function.  For example to add the BurStMisc package to the search list, you would do:

require(BurStMisc)

The same effect is achieved with:

library(BurStMisc)

There are reasons to dislike each of these — require fails to throw an error if the package is not available, while library conflates both terminology and operations.

The packages in your library have to get there from somewhere.  That somewhere is called a repository.  The main R repository is CRAN.  The function that takes packages from CRAN and puts them into your library is install.packages.  This is used like:

install.packages("BurStMisc")

CRAN is the primary repository, but not the only one.  You can even create your own.

Navigation

Navigation can be broken into a few steps.  Perhaps something like:

  • Decide a destination
  • Chart a course
  • Steer the ship
  • Keep track of where you are
  • Survive trouble

1) R-bloggers

rblogger If you’re not so sure where you want to go, then having a glance through R-bloggers might give you some hints for vacation spots.

Chart a course

Suppose you are starting on the Iberian peninsula and you want to get to India.  How to do that?

You can go south and then east when you can, like they’ve done for a while now.  Or you can go west instead.

640px-Atlantic_Ocean,_Toscanelli,_1474
“Atlantic Ocean, Toscanelli, 1474” by Bartholomew, J. G. – A literary and historical atlas of America, by Bartholomew, J. G.. Licensed under Public domain via Wikimedia Commons.

2) Task views

Each Task View outlines the CRAN functionality that is available for that specialty.  The views generally fall into two categories:

3) Rdocumentation.org

Rdocumentation gathers help files from lots of places and makes them searchable. Rdocumentation You can find functionality from the wide world of R here.  Easily.

Note that just because you don’t find what you are looking for, doesn’t mean that it doesn’t exist.  When the name of the strsplit function recently escaped me, I failed to find it here (because I didn’t know the right words to put in the search).

If you come up empty, there is always internet search (but see below).

4) sos package

The sos package performs essentially the same task as Rdocumentation but in a different way.  One difference is that while Rdocumentation starts and ends in a browser, sos starts in R and ends in a browser. (You’ll need to install sos the first time you want to use it, and put it on the search list in each session you’re using it.)

??? is the centerpiece, use it like:

> ???sudoku
found 18 matches; retrieving 1 page

You need to use quotes if there is more than one word:

???"genetic optimization algorithm"

I lied.  You don’t have to end in a browser — you can manipulate the search results in R:

srch <- ???"genetic optimization algorithm"
table(srch$Package)

The ??? operator is an alias for the findFn function.  There’s more information in the R Journal article.

5) ??

Search the help files that are on the search list with ??:

??find

produces a list of help files on the search list that contain the term (“find” in this case) in appropriate sections.

The ?? operator is an alias for the help.search function.

6) apropos

If you know or suspect part of the name of the function you are looking for, use apropos.  For instance if you think the name might contain “split”, do:

apropos("split")

The result is a vector of function names that contain the phrase.

This only looks at objects that are on the search list.

7) ls

A common use is:

ls()

which (when at the R prompt) lists the objects that are in the global environment — the first position on the search list.

Another use is:

ls(2)

This lists the objects that are in the second position of the search list.  The location on the search list can be specified by name rather than number:

ls("package:utils")
ls("file:mystuff.RData")

Another useful argument is pattern, which in my laziness I usually abbreviate to pat.

ls("package:utils", pat="zip")

The pattern argument restricts the output to objects with names that partially match it — a sort of local apropos.

The all.names argument to ls defaults to FALSE.  When it is TRUE, then objects whose names start with a dot are also printed.

As already noted, ls and objects are synonyms.

Steer the ship

640px-Columbus_Fleet_1893_Issue

“Columbus Fleet 1893 Issue” by US Post Office – US Post Office /Hi-res scan of stamp from private collection by Gwillhickers. Licensed under Public domain via Wikimedia Commons.

8) methods

R’s object-orientation (generic functions and methods) simplifies naive use, but can produce some grief for the semi-naive.

A generic function (examples are print, plot and summary) has methods specific to the class of the object given as the argument to the function (generally the first argument).

The methods function shows you the methods on the search list that are available for a generic function:

> methods(predict)
 [1] predict.ar*                predict.Arima* 
 [3] predict.arima0*            predict.glm 
 [5] predict.HoltWinters*       predict.lm 
 [7] predict.loess*             predict.mlm* 
 [9] predict.nls*               predict.poly* 
[11] predict.ppr*               predict.prcomp* 
[13] predict.princomp*          predict.smooth.spline* 
[15] predict.smooth.spline.fit* predict.StructTS* 

   Non-visible functions are asterisked

You can go the other way as well.  If you have a class and you want to know the generic functions that have methods specific to that class, then use the class argument to methods:

> methods(class="poly")
[1] makepredictcall.poly* predict.poly* 

  Non-visible functions are asterisked

methods is for S3 methods.  Similar functionality is available for S4 methods with showMethods.

methods(print) # 183 methods in my session

But:

> showMethods(print)

Function "print":
 <not an S4 generic function>
> print
function (x, ...) 
UseMethod("print")
<bytecode: 0x000000000a72ef20>
<environment: namespace:base>

The UseMethod means that this is an S3 generic.  However S3 generics can mutate to be both S3 and S4 generic:

> require(Matrix)
Loading required package: Matrix
> print
standardGeneric for "print" defined from package "base"

function (x, ...) 
standardGeneric("print")
<environment: 0x000000001592f3f8>
Methods may be defined for arguments: x
Use showMethods("print") for currently available ones.
> showMethods(print)
Function: print (package base)
x="ANY"
x="diagonalMatrix"
x="sparseMatrix"

9) getAnywhere

You may have noticed that the results of methods includes the phrase “Non-visible functions are asterisked”.  The ocean has a subsurface containing things that are not easily visible.  So does R.

Packages typically make a few functions visible, but functions that are not of general interest are left invisible.  The visible objects are exported.

The predict.poly function is listed as being non-visible.  This is less visible than having a name that begins with a dot — if we do ls of the package where it lives, it won’t appear even with all.names=TRUE:

> ls("package:stats", all.names=TRUE, pat="predict.poly")
character(0)

But at this point we don’t have a way to know what package the function is in.  Enter getAnywhere:

getAnywhere(predict.poly)

shows you the definition of the function and explains where it found it.

If you are interested only in where something lives, then just get the where component:

> getAnywhere(predict.poly)$where
[1] "registered S3 method for predict from namespace stats"
[2] "namespace:stats"

If there were more than one object on the search list with the name, it would show you all of them.  Let’s experiment:

 > predict.poly <- "want cracker"
> getAnywhere(predict.poly)$where
character(0)

What’s going on?  There should be two things by the name, but this is saying we don’t have any now.

> getAnywhere(predict.poly)
no object named ‘want cracker’ was found

Okay, this is making more sense.  Many of the navigational functions, including this one, cater to us slackers by letting us not use quotes where they logically should be.  But in this case we’ve been caught out and need to add the quotes:

> getAnywhere("predict.poly")$where
[1] ".GlobalEnv" 
[2] "registered S3 method for predict from namespace stats"
[3] "namespace:stats"

10) :::

If you want to look at (or use) a non-exported function from a particular package, then you can use the ::: operator.  For example:

stats:::predict.poly

Think of this as giving the family name in front and the given name at the back.

This is the insistent form of the :: operator, which only works for exported objects.  :: is useful for two reasons:

  • if there is (possibly) more than one object to be found by that name
  • to make code more explicit to humans

Suppose somewhere in a pile of code you run into:

funkyFunction(x, 42)

This will be quite mysterious if you are unaware of funkyFunction.  It would be much less mysterious if the code read:

pinta::funkyFunction(x, 42)

In this form both R and you know that the function lives in the pinta package (actually what you know is that it lives in the pinta namespace, but close enough).

11) find

find gives you the location on the search list of objects with a specific name:

> find("split")
[1] "package:base"

Using the exact name is the default, but the simple.words argument allows a more general search:

> find("split", simple=FALSE)
[1] "package:graphics" "package:base"

We can investigate further to see the partial matches:

> ls("package:graphics", pat="split")
[1] "split.screen"

12) args

To see the arguments (and their default values) of a function, use args:

> args(find)
function (what, mode = "any", numeric = FALSE, simple.words = TRUE) 
NULL

The args function can be thought of as an alternative to the ? operator.  The command:

?find

produces the help file for the find function.

One of my favorite uses of ? (when sos is on the search list) is:

?"???"

And if sos isn’t on the search list, it’s even better with its amusing (and wrong) suggestion of what to try.

The ? operator is an alias for the help function.

Why would you use args instead of `?`?  At least two reasons:

  • you only want a reminder of argument names or defaults
  • there isn’t a help file

The latter is often the case (probably too often) for functions written locally.

If a function has a zillion arguments, then it can be hard to find the argument that you care about in the results of args.  There’s a solution for that too.

Suppose you want to find the default value for the fill argument to read.table and you are having a hard time finding it in the results of args.  Then do:

> formals(read.table)[["fill"]]
!blank.lines.skip
> formals(read.table)[["blank.lines.skip"]]
[1] TRUE

Note that by default you need to give the full name of the argument:

> formals(read.table)[["blank"]]
NULL
> formals(read.table)[["blank", exact=FALSE]]
[1] TRUE

The last command uses the exact argument to subscripting to say that it is allowable to give an abbreviation.

If you are having a hard time with the argument names, you can do something like:

> sort(names(formals(read.table)))
 [1] "allowEscapes"     "as.is"            "blank.lines.skip"
 [4] "check.names"      "col.names"        "colClasses" 
 [7] "comment.char"     "dec"              "encoding" 
[10] "file"             "fileEncoding"     "fill" 
[13] "flush"            "header"           "na.strings" 
[16] "nrows"            "numerals"         "quote" 
[19] "row.names"        "sep"              "skip" 
[22] "skipNul"          "stringsAsFactors" "strip.white" 
[25] "text"

13) grep

If you are looking for some bit of text within the strings of a character vector, then use grep:

> grep("na", names(formals(read.table)), value=TRUE)
[1] "row.names" "col.names" "na.strings" 
[4] "check.names"

By default the result of grep is the indices of the strings that match rather than the strings themselves — hence value=TRUE in the call.

14) %in%

If instead of partial matches, you want exact matches, then %in% returns a logical vector stating if the corresponding element of the first vector is an element of the second.

> c("a", "AA", "bb", "aaa", "aa") %in% c("aa", "bb")
[1] FALSE FALSE TRUE FALSE TRUE

%in% uses match which can perform all sorts of magic.

Keep track of where you are

It is popular understanding that Columbus was the first to go west to get to India because of the then belief that the earth is flat.  It was Washington Irving in 1828 who spread that idea.  Actually Columbus was first because others thought — correctly — that India was too far away going west.

15) str

One reason that R is good at what it does is its richness of data structures.  str produces a map of an R object.

Here are a few examples to clue you in:

> str(1:100)
 int [1:100] 1 2 3 4 5 6 7 8 9 10 ...

says it is a length 100 vector ([1:100]) of integers (int), and lists the first few values.

> str(matrix(c(1,2:6),2))
 num [1:2, 1:3] 1 2 3 4 5 6

says that it is a matrix with 2 rows and 3 columns ([1:2, 1:3]) of numeric values (num), and lists all the values.

> str(array(as.character(1:6), c(2,3), list(c("r1", "r2"), NULL)))
 chr [1:2, 1:3] "1" "2" "3" "4" "5" "6"
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:2] "r1" "r2"
  ..$ : NULL

The first line says it is a matrix with 2 rows and 3 columns ([1:2, 1:3]) of character values (chr), and lists the values.  The second line says that the object has an attribute called “dimnames” that is a list of length 2.  The third and fourth lines give the two components of dimnames.  The first component is a character vector of length 2, and the second component is NULL.

> str(data.frame(matrix(c(1,2:6),2)))
'data.frame': 2 obs. of 3 variables:
 $ X1: num 1 2
 $ X2: num 3 4
 $ X3: num 5 6

The first line says that it is a data frame with 2 rows and 3 columns.  Each of the remaining lines gives the name of the column and its contents.

16) str

str is useful enough to count twice.

17) getwd

R has a sense of where it is.  That location is called the working directory.  Path names to files are understood to be relative to the working directory.  You can see the working directory with:

> getwd()
[1] "C:/Users/pat/burns-stat3/webpages/blog/simple"

Change the working directory with setwd.

18) file.choose

It is not at all unusual for me to need to specify a file name but R and I disagree — that is, what I specify doesn’t exist.  Rather than fixing my mess, it is often easier to use file.choose to print out the path and then paste the result to where I want.

Do:

file.choose()

which gives you a popup window to select the file.  The result is a character string.

Spyglass summary

Table 1 attempts to summarize how to find things in R, though some of the pegs don’t quite fit their holes.  For example, the line for global environment could apply to any item on the search list.

Table 1.

Universe Partial Exact Information
internet search engine search engine search engine
R repositories Rdocumentation.org Rdocumentation.org Rdocumentation.org
CRAN ??? ??? ???
search list apropos (name) find (location) ??
global environment pattern in ls (name) ? args str
object grep (indices or strings) %in% (logical) str

Survive trouble

The Santa Maria ran aground and met its end on Christmas Day 1492.  Bad things happen — even to brave explorers.

19) browser

I was really proud of myself last week when I wrote a function that worked the first time.  Almost always something is not right with my newly minted functions.  A useful technique to find trouble — or to check if there is trouble — is to put:

browser()

at strategic spots in the function.

When the function is run, then the browser call puts you into the frame of the function.  Do:

ls()

to see the names of the objects in the frame.

You can execute commands as if you are in the function — including making assignments.  To continue the computation, type:

c

as in “continue”.  To quit the computation and get back to the R prompt, type:

Q

as in “Quit”.

An alternative to browser is recover, used like:

recover()

The difference is that recover allows you to look not only inside the frame of the function in which it was called, but in the frames of the chain of functions that led to the call.  If you put the call to recover in function foo, and foo was called by funB which was called by funA, then you can look in the frames of foo, funB and funA.

In this case you are given a numbered menu and you select the number you want, or 0 to exit.  Once you’ve selected a number, it is just like being in browser.  If you say “c” to end the browser session, then you get back to the menu.

20) The R Inferno

The R Inferno charts quite a few rocks that you might run aground upon.

21) Hacking attitude

An important tool to get around in R is to have  a hacking attitude — to try things with the idea that they probably won’t work.  With enough hacking you might even do a columbus — have a great result for the wrong reason.

If you’re looking for spice and you find gold, don’t ignore it.

See also

An introduction to R is “Impatient R”.

Pertinent chapters of Tao Te Programming include: profit from mistakes (Ch. 11), hacking (Ch. 18).

The Wikipedia article on Columbus fails to paint him as the heroic figure I was taught in elementary school.  I wonder which is more accurate.

Updates

22) sessionInfo

The sessionInfo function tells you a variety of information about the current state of your session.  Not least is the versions of the packages that you are using.

> sessionInfo()
R Under development (unstable) (2014-07-29 r66272)
Platform: x86_64-w64-mingw32/x64 (64-bit)

locale:
[1] LC_COLLATE=English_United Kingdom.1252 LC_CTYPE=English_United Kingdom.1252 
[3] LC_MONETARY=English_United Kingdom.1252 LC_NUMERIC=C 
[5] LC_TIME=English_United Kingdom.1252 

attached base packages:
[1] stats graphics grDevices utils datasets methods base 

other attached packages:
[1] Matrix_1.1-4

loaded via a namespace (and not attached):
[1] grid_3.2.0 lattice_0.20-29 tools_3.2.0

Epilogue

And they’ll never know the gold
Or the copper in your hair
How could they weigh the worth
Of you so rare

– from “World before Columbus” by Suzanne Vega

Appendix R

The code to draw Figure 1 is:

P.Rmap <- function (filename = "Rmap.png") 
{
 if(length(filename)) {
  png(file=filename, width=512, height=512)
  par(mar=rep(1, 4) + .1, xpd=TRUE)
 }
 plot.new()
 plot.window(c(-1, 1), c(-1, 1), asp=1)
 theta <- seq(0, 2 * pi, length=400)
 xy <- cbind(cos(theta), sin(theta))
 polygon(xy, col="lightblue")
 polygon(xy * .8, col="lightgreen")
 polygon(xy * .6, col="lightblue")
 polygon(xy * .4, col="lightgreen")
 polygon(xy * .2, col="lightblue")
 text(0, .7, "CRAN")
 text(0, .9, "BioConductor")
 text(xy[50,1] * .9, xy[50,2] * .9, "Omegahat", srt=-45)
 text(xy[350,1] * .9, xy[350,2] * .9, "R-forge", srt=45)
 text(xy[150,1] * .9, xy[150,2] * .9, "local repos", srt=45)
 text(xy[250,1] * .9, xy[250,2] * .9, "github", srt=-45)
 text(xy[290,1] * .9, xy[290,2] * .9, "bitbucket", srt=-15)
 text(xy[50,1] * .9, xy[50,2] * .9, "Omegahat", srt=-45)
 text(xy[80,1] * .3, xy[80,2] * .3, "search list", srt=-15)
 text(xy[100,1] * .5, xy[100,2] * .5, "library")
 text(xy[300,1] * .3, xy[300,2] * .3, "search()")
 text(xy[300,1] * .5, xy[300,2] * .5, "library()")
 text(xy[300,1] * .67, xy[300,2] * .67, "available.packages()")
 text(0, -0.05, "ls()")
 text(-.95, 1.1, "Global environment", 
  col="blue", adj=0)
 segments(xy[125,1] * 1.08, xy[125,2] * 1.08, 
  xy[125,1]*.1, xy[125,2] * .1, col="blue")
 segments(xy[335,1] * 1.15, xy[335,2] * 1.15, 
  xy[335,1]*.6, xy[335,2] * .6, col="black")
 text(xy[335,1] * 1.2, xy[335,2] * 1.2, "install.packages")
 segments(xy[265,1] * 1.15, xy[265,2] * 1.15, 
  xy[265,1]*.4, xy[265,2] * .4, col="black")
 text(xy[265,1] * 1.2, xy[265,2] * 1.2, "require")
 if(length(filename)) {
  dev.off()
 }
}
5 replies
  1. Elizabeth says:

    How sad I am that I did not discover the R Inferno, and your blog, whilst still in graduate school, when it truly could have been a salve to my suffering. Now it is still a great comfort, but to much lesser angst. Thank you for your work on this subject.

    Reply
    • Patrick Burns says:

      Elizabeth,

      Thanks for the kind words. I’m open to ideas of how to make “The R Inferno” better known. It seems there are a lot of people suffering without it when they could be suffering with it.

      Reply
      • Elizabeth says:

        You are most welcome for the well-deserved appreciation.

        I wish I knew how to make things well known. It would be very helpful in my field. But alas, I’m stuck in my circle of nerds on the Internet.

        I might forward it to my old professor at the UW who teaches some of the intro classes. Maybe she will put it on her syllabus.

        Reply

Trackbacks & Pingbacks

  1. […] also mention that R has other built-in ways of finding functions beyond ??, and as Pete linked to, Pat Burns’ guide to them is […]

  2. […] 2) Mnogi ste se že srečali s programiranjem v prosto dostopnem statističnem paketu R, ki je verjetno ena boljših stvari, ki se je statistikom in ekonometrikom zgodila v zadenjm desetletju. Ker je paket precej svojsko napisan, prav pride vedeti, kako in s katerimi ukazi lahko v njem navigiramo. Več o tem najdete tukaj. […]

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *

© Copyright - Burns Statistics