Unable to edit R function - r

I am trying to edit and save a function from an R package. So far I have tried
my_edited_func <- edit(package_func)
my_edited_func <- package_func
fix(my_edited_func)
In both cases, a text editor opens up, where I can make changes, but when exiting with :wq, I get the following error:
Error in .External2(C_edit, name, file, title, editor) :
problem with running editor vi
I am using R 3.3.1 on OS X 10.11

Fixing the Editor
We're going to modify the R_HOME/etc/Rprofile.site file to change default editors from vi to vim:
Rscript -e "R.home()"
You probably will get:
[1] "/Library/Frameworks/R.framework/Resources"
Then use:
vim /Library/Frameworks/R.framework/Resources/etc/Rprofile.site
Find:
options(editor="vi")
And switch it to:
options(editor="/usr/bin/vim")
Misc notes
To edit a function simply do:
my_edited_func = edit(package_func)
From now on, call my_edited_func().
In RStudio:
In Terminal:
Though, for more control (and more effective saves) note the following...
Free Function Info
You can grab the function source by just typing the function name:
e.g.
Declaring trash
trash = function(x = TRUE){
!x
}
Calling:
trash
Output:
function(x = TRUE){
!x
}
Grabbing the source here and making a slight change is then possible, e.g.:
trash2 = function(x = TRUE){
x
}

Related

Suppress messages in markdown, but not in R console

I currently use the following header:
```{r, message=FALSE}
foo <- function(x) message(x)
for(i in 1:10) foo(i)
```
Inside this code chunk, there is a loop over simulated scenarios, with message() function that prints status of currently executed scenario.
I would like to suppress those messages from display in RStudio and final HTML output, but I still want to control the simulation progress and see the message() output in console. Is this achievable? Maybe with other arguments/functions?
You can write/append status to a file (this is a workaround solution, there should be a more direct answer).
For example:
file <- file("status.txt", open = "wt")
sink(file, type = "message")
message("all good")
In this example message won't be displayed - it'll be written to a status.txt file.
In you're using specific function and iterating over a set you can try this example:
foo <- function(x) {
message(x)
}
file <- file("status.txt", open = "wt")
sink(file, type = "message")
for(i in 1:3) {
foo(i)
}
Function foo should return (message) value, however it appends it to a status.txt file.
You can track changes in status.txt file using bash tail command with -f argument. First send R to background and then use tail -f status.txt in your console.
One approach would be to put this in the start of your file.
mymessage <- function (text) {
if(knitr::opts_knit$get('out.format') != NULL) message(text)
}
There are various ways to know if you are within knitr, recent versions have knitr::is_latex_output and similar.

How to access/copy the View function?

I'm currently working on an add in for RStudio which opens an "enchanced" view of a data frame in Shiny, allows you to filter and select columns, then passes that code to the command line wrapped in View().
One feature which was suggested to me was to replace the default View in RStudio when the package is loaded to always load my new viewer.
I wanted this, but also to preserve the ability to use RStudio's View if you wanted. So I tried code like this:
View <- function(data_in, replace = T){
if (replace){
print('example')
}else{
utils::View(data_in)
}
This does not work, however, as utils::View is not the same as the View in RStudio. However, a search for ?View only gets the utils version. I'm assuming RStudio is overwriting View when loading, but I have no idea how to access it. I'd be happy to copy the function into something called save_view (or similar) but don't know how to access it! Entering View into the command line gives me the following code
function (...)
.rs.callAs(name, hook, original, ...)
<environment: 0x516d648>
But copying that to a new function will just give me something that errors (I'm wondering if it's something to do with the environment the function exists on)
RStudio replaces the internal View function with the one you saw. You can get it using
RStudioView <- as.environment("package:utils")$View
If you call that one, it should do what RStudio does.
You get the original one using utils::View.
This seems to be the source of the View() (from utils):
function (x, title)
{
check <- Sys.getenv("_R_CHECK_SCREEN_DEVICE_", "")
msg <- "View() should not be used in examples etc"
if (identical(check, "stop"))
stop(msg, domain = NA)
else if (identical(check, "warn"))
warning(msg, immediate. = TRUE, noBreaks. = TRUE, domain = NA)
if (missing(title))
title <- paste("Data:", deparse(substitute(x))[1])
as.num.or.char <- function(x) {
if (is.character(x))
x
else if (is.numeric(x)) {
storage.mode(x) <- "double"
x
}
else as.character(x)
}
x0 <- as.data.frame(x)
x <- as.list(format.data.frame(x0))
rn <- row.names(x0)
if (any(rn != seq_along(rn)))
x <- c(list(row.names = rn), x)
if (!is.list(x) || !length(x) || !all(sapply(x, is.atomic)) ||
!max(lengths(x)))
stop("invalid 'x' argument")
if (grepl("darwin", R.version$os))
check_for_XQuartz()
invisible(.External2(C_dataviewer, x, title))
}
And very clearly it's calling the C_dataviwer and this is the dataviewer https://support.rstudio.com/hc/en-us/articles/205175388-Using-the-Data-Viewer#starting-the-viewer
Edit:
Here's the actual code of dataviewer https://github.com/rstudio/rstudio/blob/5719361179d1020dc3157c4e24b21bcd17c483e6/src/cpp/session/modules/data/DataViewer.cpp

.First function in R

I don't understand the point of .First function in R. My reason is any code in .Rprofile will be sourced and executed when R starts up anyway.
this
.First<-function(){
library('devtools')
}
and this
library('devtools')
in .Rprofile have exactly the same effect.
However, here is an example that shows .First can make a difference:
example 1, you can see X11.options()$type correctly becomes Xlib as set in .Rprofile
>> cat .Rprofile
.First <- function() {
library(devtools)
}
setHook(
packageEvent("grDevices", "onLoad"),
function(...) grDevices::X11.options(type="Xlib")
)
>> Rscript -e 'X11.options()$type'
[1] "Xlib"
example 2, you can see X11.options()$type is still cairo, the setHook in .Rprofile didn't take effect
>> cat .Rprofile
library(devtools)
setHook(
packageEvent("grDevices", "onLoad"),
function(...) grDevices::X11.options(type="Xlib")
)
>> Rscript -e 'X11.options()$type'
[1] "cairo"
in what case do I absolutely have to use .First function?
why .First made a difference in the example above?
Thanks!
It may be unnecessary but it does provide yet another place to modify the startup. It certainly doesn't hurt having it.
I generally run R in different directories to keep things separated; link to a common .Rprofile; and use .First to tailor the current R run environment to the specific problem I'm working on. If .First action wasn't available I'd have to create one.
One benefit of putting startup code in .First() instead of .RProfile is that you can use local variables which won't stay in your Global environment after .First() completes.
For example, my .First() displays the list of .R files on the project directory in as many columns as will fit:
localFiles <- list.files(pattern = "\\.R$", ignore.case = TRUE)
maxChars <- max(nchar(localFiles))
numCols <- as.integer((options("width")$width-2) / (1 + maxChars)) # how many columns will fit?
fmt <- sprint(" %%-%d", maxChars) # left justified in each column
for (nn in localFiles) {
if ((match(nn, localFiles) %% numCols) == 1) cat(" ") # indent each row
cat(sprint(fmt, nn))
if ((match(nn, localFiles) %% numCols) == 0) cat("\n") # end of row
}
if (length(localFiles) %% numCols != 0) cat("\n") # end last row if not complete
Since this is in .First(), all of the temporary variables get cleaned up when the function returns and the Global environment remains clean.
R sources Rprofile.site then either project-level or user-level .Rprofile and then evaluates .First (Rstudio Support).
.First is useful to include in Rprofile.site if you want to trigger an action (site-wide) that is conditional on user or project .Rprofile.
Example: renv is activated by project-level .Rprofile.
This code will print a message indicating the location of the renv cache or will alert the user that renv hasn't been activated.
if (interactive()) {
.First <- function() {
if ("RENV_PROJECT" %in% names(Sys.getenv())) {
cat("\nLinked to renv cache:\n")
cat("-", renv::paths$cache(), "\n\n")
} else {
cat("\n*** Warning: you are not in an active renv project! ***\n")
cat("- Some functions may be unavailable.\n\n")
}
}
}

TclTk object in R

I'm new to R (and programming in general), so apologies if this has been answered elsewhere. I was not able to find an answer via searching, but any help or direction would be great!
I'm trying to make a clickable interface in R, where I can have users click to find a file of choice that proceeds to get automatically analyzed in R.
Here's what I'm having trouble with:
require(tcltk)
getfile <- function() {name <- tclvalue(tkgetOpenFile(
filetypes = "{{CSV Files} {.csv}}"))
if (name == "") return;
datafile <- read.csv(name,header=T)
}
tt <- tktoplevel()
button.widget <- tkbutton(tt, text = "Select CSV File to be analyzed", command = getfile)
tkpack(button.widget)
# The content of the CSV file is placed in the variable 'datafile'
Yet when I try to execute it, and click on a CSV file of interest after the button pops up, nothing happens. By that I mean R gives me the error below when I type in datafile.
Error: object 'datafile' not found
Once again, any help is much appreciated. Thanks!
The top level object has an environment in which you can store things, keeping them local to the GUI. Give your callbacks that object as an argument:
# callback that reads a file and stores the DF in the env of the toplevel:
getfile <- function(tt) {name <- tclvalue(tkgetOpenFile(
filetypes = "{{CSV Files} {.csv}}"))
if (name == "") return;
tt$env$datafile <- read.csv(name,header=T)
}
# callback that does something to the data frame (should check for existence first!)
dosomething <- function(tt){
print(summary(tt$env$datafile))
}
# make a dialog with a load button and a do something button:
tt <- tktoplevel()
button.choose <- tkbutton(tt, text = "Select CSV File to be analyzed", command = function(){getfile(tt)})
tkpack(button.choose)
button.dosomething <- tkbutton(tt, text = "Do something", command = function(){dosomething(tt)})
tkpack(button.dosomething)
That should be fairly robust, although I'm not sure if there's anything already in the environment that you should beware stomping on, in which case create an environment in that environment and use that for your local storage.
If you want to quit the dialog and save things for the user, prompt for a name and use assign to store them in .GlobalEnv on exit.

Interactively ask user for filename before saving file

I want to save the my tab delim files manually. I mean that I want user to choose the directory and file name when he wants to save the data. (For an example I have merged individual files into single file and want to save it.)
Usually I use write.table but in write.table we define the directory path and file name within that function but I want a function in which user can save file with any name in his desired directory.
Just use the file.choose() function,like this:
write.table(yerdata, file = file.choose(new = TRUE))
On Windows, at least, that will bring up a dialog for save-as commands.
Annoyingly the tcltk package doesn't have a function for 'Save As', it only has a file selector for choosing an existing file.
Luckily you can take the DIY approach via some tcl calls:
require(tcltk)
write.table(yerdata,file = tclvalue(tcl("tk_getSaveFile")))
The tk_choose.files function source could be used as a template to write a nicer interface to tcl("tk_getSaveFile") if needed. Does seem to be a glaring omission in package:tcltk though...
Using gWidgets:
gfile("Save yerdata", type = "save", handler = function(h, ...)
{
write.table(yerdata, file = h$file)
})
One (perhaps less than ideal) option would be to use readline to prompt the user for the full path and file name (or just the file name if you want to programmatically choose the directory) and then simply pass that value on the write.table. Here's a sketch:
FILE_PATH <- readline(prompt = "Enter a full path and file name: ")
#Some checking to make sure you got a valid file path...
write.table(yerdata, file = FILE_PATH)
Note that as per ?readline this will really only work when running R interactively.
As it is 2017 now, the tcltk2 package is an improvement of tcltk:
library(tcltk2)
filename <- tclvalue(tkgetSaveFile())
if (!nchar(filename)) {
tkmessageBox(message = "No file was selected!")
} else {
tkmessageBox(message = paste("The file selected was", filename))
}
And the use of filters, let's say one should only save as JPG/JPEG:
jpeg_filename <- tclvalue(
tkgetSaveFile(initialfile = "foo.jpg",
filetypes = "{ {JPEG Files} {.jpg .jpeg} } { {All Files} * }")
)

Resources