How to debug (placing break point,etc) an installed R package in RStudio? - r

I need to run a function line-by-line to understand how it works. But the function is part of an installed package and I don't know where R stores the source of the installed packages (say MultiPhen). I am using RStudio 0.98.501 and R 3.0.2 in Ubuntu 12 (64it). Apparently source code of installed packages are not stored, right? Sorry if it is a naive question, I am new to R.
If the sources are not stored, is there anyway to re-install a package with source and debug it (basically place a break point).
Thanks,
Kayhan

Look at trace. Here is an example adding a breakpoint at the fourth statement in the base package function var. Here we ask trace to invoke the function browser at the sixth statement:
> trace(var, browser, at=6)
Tracing function "var" in package "stats"
[1] "var"
> var(1:10)
Tracing var(1:10) step 6
Called from: eval(expr, envir, enclos)
Browse[1]> n
debug: if (is.data.frame(y)) y <- as.matrix(y) else stopifnot(is.atomic(y))
Browse[2]> n
debug: stopifnot(is.atomic(y))
Browse[2]> n
debug: .Call(C_cov, x, y, na.method, FALSE)
Browse[2]> n
[1] 9.166667
Remember to untrace when you're done. You can do fairly complex stuff with trace, though in most cases trace(fun.name, browser) is probably enough.
Alternatively, you can just load the package and type the name of the function on the command line like so:
> var
function (x, y = NULL, na.rm = FALSE, use)
{
if (missing(use))
use <- if (na.rm)
"na.or.complete"
else "everything"
na.method <- pmatch(use, c("all.obs", "complete.obs", "pairwise.complete.obs",
"everything", "na.or.complete"))
if (is.na(na.method))
stop("invalid 'use' argument")
if (is.data.frame(x))
x <- as.matrix(x)
else stopifnot(is.atomic(x))
if (is.data.frame(y))
y <- as.matrix(y)
else stopifnot(is.atomic(y))
.Call(C_cov, x, y, na.method, FALSE)
}
<bytecode: 0x000000000928ad30>
<environment: namespace:stats>
You can then copy that into your editor and play around with it, add your browser statement, and step through the results.

I think that when when you type install.packages('MultiPhen') you get a binary version of the package. I think that there is no way to set a breakpoint and step thru code with that version of the package.
All R packages are open source, and the source is available on the CRAN page for the package. For example, this is the CRAN page for MultiPhen. If you click on the link next to the text "Package source:" you will download the source.
In terms of what to do when you have the source: all R packages have the same directory structure. What matters for your situation is that all the R code for the package is in the directory called "R".
I recommend uninstalling the package from RStudio and sourcing the code in the directory "R", setting breakpoints and stepping thru code as you see fit.
Please let us know if this solves your problem.

I found a easy way to do this. First you write a script to recall the function, and then set a breakpoint. Run the script, and it you stop at the breakpoint. Then you can see there are different options to run the code. next line, step into the function, continue, stop...And now you can run the code line by line, and run into to your function.

Related

R: Patching a package function and reloading base libraries

Occasionally one wants to patch a function in a package, without recompiling the whole package.
For example, in Emacs ESS, the function install.packages() might get stuck if tcltk is not loaded. One might want to patch install.packages() in order to require tcltk before installation and unload it after the package setup.
A temp() patched version of install.packages() might be:
## Get original args without ending NULL
temp=rev(rev(deparse(args(install.packages)))[-1])
temp=paste(paste(temp, collapse="\n"),
## Add code to load tcltk
"{",
" wasloaded= 'package:tcltk' %in% search()",
" require(tcltk)",
## Add orginal body without braces
paste(rev(rev(deparse(body(install.packages))[-1])[-1]), collapse="\n"),
## Unload tcltk if it was not loaded before by user
" if(!wasloaded) detach('package:tcltk', unload=TRUE)",
"}\n",
sep="\n")
## Eval patched function
temp=eval(parse(text=temp))
# temp
Now we want to replace the original install.packages() and perhaps insert the code in Rprofile.
To this end it is worth nothing that:
getAnywhere("install.packages")
# A single object matching 'install.packages' was found
# It was found in the following places
# package:utils
# namespace:utils
# with value
#
# ... install.packages() source follows (quite lengthy)
That is, the function is stored inside the package/namespace of utils. This environment is sealed and therefore install.packages() should be unlocked before being replaced:
## Override original function
unlockBinding("install.packages", as.environment("package:utils"))
assign("install.packages", temp, envir=as.environment("package:utils"))
unlockBinding("install.packages", asNamespace("utils"))
assign("install.packages", temp, envir=asNamespace("utils"))
rm(temp)
Using getAnywhere() again, we get:
getAnywhere("install.packages")
# A single object matching 'install.packages' was found
# It was found in the following places
# package:utils
# namespace:utils
# with value
#
# ... the *new* install.packages() source follows
It seems that the patched function is placed in the right place.
Unfortunately, running it gives:
Error in install.packages(xxxxx) :
could not find function "getDependencies"
getDependencies() is a function inside the same utils package, but not exported; therefore it is not accessible outside its namespace.
Despite the output of getAnywhere("install.packages"), the patched install.packages() is still misplaced.
The problem is that we need to reload the utils library to obtain the desired effect, which also requires unloading other libraries importing it.
detach("package:stats", unload=TRUE)
detach("package:graphics", unload=TRUE)
detach("package:grDevices", unload=TRUE)
detach("package:utils", unload=TRUE)
library(utils)
install.packages() works now.
Of course, we need to reload the other libraries too. Given the dependencies, using
library(stats)
should reload everything. But there is a problem when reloading the graphics library, at least on Windows:
library(graphics)
# Error in FUN(X[[i]], ...) :
# no such symbol C_contour in package path/to/library/graphics/libs/x64/graphics.dll
Which is the correct way of (re)loading the graphics library?
Patching functions in packages is a low-level operation that should be avoided, because it may break internal assumptions of the execution environment and lead to unpredictable behavior/crashes. If there is a problem with tck/ESS (I didn't try to repeat that) perhaps it should be fixed or there may be a workaround. Particularly changing locked bindings is something to avoid.
If you really wanted to run some code at the start/end of say install.packages, you can use trace. It will do some of the low-level operations mentioned in the question, but the good part is you don't have to worry about fixing this whenever some new internals of R change.
trace(install.packages,
tracer=quote(cat("Starting install.packages\n")),
exit=quote(cat("Ending install packages.\n"))
)
Replace tracer and exit accordingly - maybe exit is not needed anyway, maybe you don't need to unload the package. Still, trace is a very useful tool for debugging.
I am not sure if that will solve your problem - if it would work with ESS - but in general you can also wrap install.packages in a function you define say in your workspace:
install.packages <- function(...) {
cat("Entry.\n")
on.exit(cat("Exit.\n"))
utils::install.packages(...)
}
This is the cleanest option indeed.

R package 'biomod2' cannot find file when executing plot function

I am attempting to use the plot() function in the biomod2 package, following a vignette here (http://finzi.psych.upenn.edu/usr/share/doc/library/biomod2/doc/Simple_species_modelling.pdf). Below is the error I am getting:
getwd()
# [1] "/home/gjanzen/Documents/Hufford/Drought/Data/Layers"
plot(myBiomodData)
Error in getExportedValue(pkg, name) : cannot open file
'~/R/x86_64-pc-linux-gnu-library/3.3/viridisLite/data/Rdata.rdb': No
such file or directory In addition: Warning message: In
getExportedValue(pkg, name) : restarting interrupted promise
evaluation
I have confirmed that the Rdata.rdb exists, in the following directory:
f <- file.choose()
f
# [1] "/home/gjanzen/R/x86_64-pc-linux-gnu-library/3.3/viridisLite/data/Rdata.rdb"
So, to me, it looks like the plot() function is looking in the wrong place. How can I change where this function looks for Rdata.rdb? Can I alter the path somehow? Or would changing my working directory fix this?
PS - This is my first post on Stack Overflow, so please forgive any mistakes in etiquette, and/or feel free to point them out to me so that I do not repeat them.
I think that the first thing to try is to reinstall the package viridisLite that seems to be the one that is causing troubles.
install.packages('viridisLite', dep = TRUE)
If this not solves the issue you should try to open a new plotting device threw x11() to check if the issue is not coming from the R (resp. RStudio) plotting device itself.

R: Sometimes system.file not working as documented

The system.file commands in my package examples sometimes fail unpredictably, while passing at other times. I do not understand why.
I typically use:
> system.file("examples", "trees.xml", package="RNeXML", mustWork=TRUE)
which usually works, but sometimes fails (even in an interactive session):
Error in system.file("examples", "trees.xml", package = "RNeXML", mustWork = TRUE) :
no file found
when it is failing, I can get this to work:
> system.file("examples", "trees.xml", lib.loc = .libPaths()[1], package="RNeXML", mustWork=TRUE)
[1] "/home/cboettig/R/x86_64-pc-linux-gnu-library/3.0/RNeXML/examples/trees.xml"
Which doesn't make any sense to me, because the documentation of system.file says that it checks libPaths automatically if no value for lib.loc is provided.
So why does it work if I give the .libPaths()[1] explicitly?
It seems like explicitly telling my package to use the first path, .libPaths()[1], would be less stable.
Since this is a heisenbug, set options(error = recover) and when prompted for a frame number, pick the one that brings you into system.file. (For more on what I'm about to explain, see Hadley's Exceptions and Debugging tutorial.) Then step through using the debugger and determine if packagePath gets loaded correctly using find.package(package, lib.loc, quiet = TRUE). I inspected this latter function and couldn't find anything immediately wrong, so it may be something system-specific. Could you post your sessionInfo()?
If packagePath is fine, then the answer lies somewhere in the rest of system.file's body:
FILES <- file.path(packagePath, ...)
present <- file.exists(FILES)
if (any(present))
FILES[present]
else ""
This would make life very hard for us since I doubt there are problems with any of these functions. If packagePath is not what you expect, you can use the recover frame number prompt again to dive back into system.file, and this time type debug(find.package) so you can step through that function. Inspect dirs and paths after the for (lib in lib.loc), and step through the few ifs that follow.
If none of these work, and you don't spot any mischief (which is very hard with the transparency of a step-by-step debugger), you can always try to dump.frames and upload the file for us. I am not sure how useful it will be, since even if we install the same packages, there may be path issues, but it's worth a shot.
Finally, if you don't care about all of the above, a hack that works would be:
trees_path <- ""
for(lib in .libPaths()) {
trees_path <- system.file("examples", "trees.xml", lib.loc = lib, package="RNeXML", mustWork = FALSE)
if (trees_path != "") break;
}
if (trees_path == "") stop("examples/trees.xml not found using any library paths")

What is the cause of "Error in .C("unlock solver")" Error in deSolve Package?

I have been using the deSolve package in a MCMC algorithm to estimate parameters in an ODE and wrote the functions used in the solver in C to speed up the algorithm. Sometimes, but not always I get the error Error in .C("unlock solver") when running the ode function. I am able to successfully compile and link the C files using the commands
system("R CMD SHLIB [insert-file-path]")
dyn.load("[dll-file-path]")
but when I try to solve the ODE using the dll file, the error is thrown. Then, even when running a simple script like the one below, I get the same error. I think the issue is related to using the compiled code, but I don't know how and cannot find any references on this error.
> require(deSolve)
> initVal <- c(y=1)
> times <- seq(0, 1, 0.001)
> parms <- c(k=1)
> model1 <- function(t, y, parms){
+ with(as.list(c(y, parms)),{
+ dy <- -k*y;
+ list(c(dy))
+ })
+ }
> out <- ode(y=initVal, times=times, parms=parms, func=model1)
Error in .C("unlock_solver") :
"unlock_solver" not resolved from current namespace (deSolve)
Partial Solution
If I restart R and only load the DLL using the dyn.load function, but don't compile the code, the ode function runs without an error. This fixes my problem, but I still have no idea why.
Edit:
REAL solution from Thomas Petzoldt on the R help list:
[The error] occurs, if package deSolve is loaded after the compiled model... The solution is to load deSolve before [before loading DLL's], ideally at the very beginning of your script, and at least before loading/unloading the DLL/.so
If that doesn't work, the below might as well (old answer):
I have found a somewhat inelegant solution.
The problem seems to be that the "unlock_solver" function within deSolve is somehow not being accessed correctly. You can unload and reload the entire deSolve.so file, rather than restarting R.
To do this you can use something like:
require(deSolve)
# encounter error
library.dynam.unload("deSolve", libpath=paste(.libPaths()[1], "//deSolve", sep=""))
library.dynam("deSolve", package="deSolve", lib.loc=.libPaths()[1])
You'll need to replace ".libPaths()[1]" with wherever you have installed deSolve, if it isn't in the first element of your .libPaths variable.
This is something of a sledge hammer, though. I've sent out a request to the r-help list asking if there is some way to either change where R looks for "unlock_solver", or to just unload/reload a portion of deSolve.
Make sure you have the following packages installed (at the beginning of your script) to compile the .dll file.
packages <- c("deSolve","coda", "adaptMCMC")
if(require(packages)){
install.packages(packages,dependencies = T)
}
ppp <- lapply(packages,require,character.only=T)
First remove the current .dll file in your wdir
c_compile <- "your_c_file"
dyn.unload(paste0(c_compile,".dll")) # unload dll (Windows only)
Then compile the C file and the .dll
system(paste0("R CMD SHLIB ",c_compile,".c"))
dyn.load(paste0(c_compile,".dll"))# Load dll (Windows only)

extracting source code from r package

I am trying to install the r package sowas and unfortunately it is too old to implement in the new versions of r.
According to the author you can use the package using the source() function to gain access to the code but I have not been able to figure out how to do that.
Any help is appreciated.
Here is a link to the package I described as it is not a CRAN package: http://tocsy.pik-potsdam.de/wavelets/
The .zip file is a windows binary and as such it won't be too interesting. What you'll want to look at is the contents of the .tar.gz archive. You can extract those contents and then look at the code in the R subdirectory.
You could also update the package to work with new versions of R so that you can actually build and install the package. To do so you could unpack the .tar.gz as before but now you'll need to add a NAMESPACE file. This is just a plaintext file at the top of the package directory that has a form like:
export(createar)
export(createwgn)
export(criticalvaluesWCO)
export(criticalvaluesWSP)
export(cwt.ts)
export(plot.wt)
export(plotwt)
export(readmatrix)
export(readts)
export(rk)
export(wco)
export(wcs)
export(writematrix)
export(wsp)
Where you have an export statement for any function in the package that you actually want to be able to use. If a function isn't exported then the functions in the package still have access to that function but the user can't use it (as easily). Once you do that you should be able to build and install the package.
I took the liberty of doing some of this already. I haven't actually taken the time to figure out which functions are useful and should be exported and just assumed that if a help page was written for the function that it should be exported and if there wasn't a help page then I didn't export it. I used Rd2roxygen to convert the help pages to roxygen code (because that's how I roll) and had to do a little bit of cleanup after that but it seems to install just fine.
So if you have the devtools package installed you should actually be able to install the version I modified directly by using the following commands
library(devtools)
install_github("SOWAS", "Dasonk")
Personally I would recommend that you go the route of adding the NAMESPACE file and what not directly as then you'll have more control over the code and be more able to fix any problems that might occur when using the package. Or if you use git you could fork my repo and continue fixing things from there. Good luck.
If you want to see the source code of a particular function, then just type the name of the function without the braces and press enter. You will see the code.
For example type var in command prompt to see it's code.
> var
function (x, y = NULL, na.rm = FALSE, use)
{
if (missing(use))
use <- if (na.rm)
"na.or.complete"
else "everything"
na.method <- pmatch(use, c("all.obs", "complete.obs", "pairwise.complete.obs",
"everything", "na.or.complete"))
if (is.na(na.method))
stop("invalid 'use' argument")
if (is.data.frame(x))
x <- as.matrix(x)
else stopifnot(is.atomic(x))
if (is.data.frame(y))
y <- as.matrix(y)
else stopifnot(is.atomic(y))
.Call(C_cov, x, y, na.method, FALSE)
}
<bytecode: 0x0000000008c97980>
<environment: namespace:stats>

Resources