This question is for those of you who happen to use R, on a Mac, in combination with Macromate's [Textmate](http://macromates.com/) text editor and the "R" Bundle. All of which are nifty, needless to say, but that's beside the point for now :-)
I've got a .RProfile file sitting in my default "~" startup directory, and it's got a number of useful functions in it I like to have access to when writing R scripts. But I also use Textmate for most of my writing, and the cmd-R functionality to to run my scripts within Textmate.
At the moment, I don't know how to tell Textmate where my .Rprofile is.
Is there a way--most likely through Textmate's Bundle settings--that I can point Textmate to my .RProfile so I don't have to write my functions into every script on a per-script basis?
OR
Is it actually better to include any custom functions in any script I write, so that anyone with a basic R setup can source and run my scripts?
I feel like I must be missing a dead-easy setting or config file here within either Textmate or the R environment it calls to run my scripts.
Thanks so much in advance!
The R Bundle Developer is apparently working on this (see this Post on the Mailing List) but it's not available at the moment.
In the meantime, you have a couple of choices.
First, you can create a new bundle (e..g, "briandk-R") then create a snippet w/in that bundle either with 'source($1)' or just hardcode the file you want to source instead of the placeholder (so, e.g., "source("~/some_file_to_source.R"). If you do the latter, then you can configure TM to source your file via a tab trigger (in the Bundle Editor, toggle over to 'settings' (upper left hand corner) and type "source.r, source.rd.console" in the 'Scope Selector' field then choose a few letters for your tab trigger (e.g., "src.")
If you don't want to do that, go to the 'Rdaemon' Directory (which is either in your home directory or in ~/Library/Application Support/Rdaemon). Look in this directory and you will see another directory called "daemon.' In there is a file called "start.r" which lists the files that are sourced upon starting R from the Rdaemon. You know what to do from there. (Note: This directory also contains a couple of other scripts which contain initial settings; you might wish to have a look at those as well)
The first part of Doug's response offers the simplest immediate solution... add
source('/Users/briandk/.Rprofile')
to the head of any .r files you want those functions in... with that one line of code, you get your utility functions. Of course, that only helps if you're running the whole TM file.
Ideally, the bundle will be updated... perhaps to support a shell variable via TM's preferences???
TM_RPROFILE
which could be set to the path to your .Rprofile file.
I just hacked this into tmR.rb with just 2 lines of code. To implement this, go to ~/Library/Application Support/TextMate/Pristine Copy/Bundles/ and Show the Contents of R.tmbundle
In there, you'll find support/tmR.rb
in my version, near line 112, you should change
tmpDir = File.join(ENV['TMP'] || "/tmp", "TM_R")
recursive_delete(tmpDir) if File.exists?(tmpDir) # remove the temp dir if it's already there
Dir::mkdir(tmpDir)
# Mechanism for dynamic reading
# stdin, stdout, stderr = popen3("R", "--vanilla", "--no-readline", "--slave", "--encoding=UTF-8")
stdin, stdout, stderr, pid = my_popen3("R --vanilla --slave --encoding=UTF-8 2>&1")
# init the R slave
stdin.puts(%{options(device="pdf")})
stdin.puts(%{options(repos="#{cran}")})
to
tmpDir = File.join(ENV['TMP'] || "/tmp", "TM_R")
recursive_delete(tmpDir) if File.exists?(tmpDir) # remove the temp dir if it's already there
Dir::mkdir(tmpDir)
rprofile = (ENV['TM_RPROFILE'] == nil) ? "" : "source('" + ENV['TM_RPROFILE'] + "')"
# Mechanism for dynamic reading
# stdin, stdout, stderr = popen3("R", "--vanilla", "--no-readline", "--slave", "--encoding=UTF-8")
stdin, stdout, stderr, pid = my_popen3("R --vanilla --slave --encoding=UTF-8 2>&1")
# init the R slave
stdin.puts("#{rprofile}")
stdin.puts(%{options(device="pdf")})
stdin.puts(%{options(repos="#{cran}")})
Just added 2 lines there... the one that begins "rprofile =" and the one that includes "#{rprofile}"
-Wil
Related
Using python, if I need the absolute path from the context of the current running script all I need to do is to add the following in the code of that script:
import os
os.path.abspath(__file__)
This is very useful as having the absolute path I can then use os.path.join to form new absolute paths for my project components (inside the project directory tree) and more interesting is that everything will continue to work without any problem no matter where the package directory is moved.
I need to achieve the very same thing using R programming, that is obtaining the absolute path of the current running R script ( = the absolute path of its file on the disk). But trying to do the same in R turns out to be quite challenging, at least for me as a rather beginner in R.
After a lot of googling, I tried to use the reticulate package to call Python from R but __file__ is not available there, then I found a few threads on Stackoverflow suggesting to play with the running Stack and others suggesting the use of normalizePath. However none of these worked for me when the entire project package is transferred from one directory to another.
Therefore, I would like to know if for example you have the following file/directory tree
base_dir ( = /home/usr1/apps/R/base_dir)
|
|
|___ myscript.R (this is my R script to be run)
|___ data (this is a directory)
|___ sql (this is a directory)
Is there any solution allowing to add something in the code of myscript.R so that inside the script the program can always know that the base directory is /home/usr1/apps/R/base_dir and if later this base directory is moved to another directory then there is no need to change the code and the program would be able to find correctly the new base directory?
R has in general no way of finding this path, because there is no equivalent to Python’s __file__ in R.
The closest you can get is to look at commandArgs() and laboriously extract the script filename (which requires different handling depending on how the script was launched!). But this will fail if the script was executed in RStudio, and it will fail after calling setwd().
Other solutions (such as the ‘here’ package) rely on heuristics and specific project structures.
But luckily there’s actually a solution that will always work: use ‘box’ modules.
With modules, you’ll always be able to get the path of the current script/module via box::file(). This is the closest equivalent to Python’s __file__ you’ll get in R, and it always works — as long as you’re using ‘box’ modules consistently.
(Internally the ‘box’ package requires complex logic to determine the value of the file() function in all circumstances; I don’t recommend replicating it, it’s too complex. For the curious, the bulk of the relevant logic is in R/loaded.r.)
If you are running the script using Rscript you can use getwd().
#!/usr/bin/Rscript
getwd()
# or assign it to a variable
base_dir = getwd()
you can run it from the command line using one of the following
./yourscript.R
# or
Rscript yourscript.R
Note however, this only works if you run the script from inside the folder, the file is in.
cd ~
./script.R
# "/home/usr1"
cd /
/home/usr1/script.R
# "/"
For a more elaborate option you could consider https://stackoverflow.com/a/55322344/3250126
I'm trying to run a compiled cpp file in my R program using system2(). The documentation for the cpp suggests that it's just one big command, so I'm thinking I'm not supposed to use the stdout or stder options in sys2.
the required network.nodes and network.edges files are there in the /files folder
I can run the system2() line but it doesn't output anything
I previously compiled the socialrank.cpp and put it in the /exe folder using Cygwin or cmd prompt maybe (g++ -o socialrank socialrank.cpp)
Guidance:
- To run the algorithm, simply run:
./socialrank summary_stats.txt graphname > debug.log
(You need to have the files graphname.nodes and graphname.edges)
My code (let me know if you need to see more):
> nodelist %>% write_delim("./files/network.nodes", col_names = F)
> edgelist %>% write_delim("./files/network.edges", col_names = F)
> #system("../exe/socialrank ../files/summary_stats.txt ../files/network") #I think this code is for macs??
> system2("./exe/socialrank ./files/summary_stats.txt ./files/network") #Is this how you correct relative file directories for Windows?
So nothing is being output into the /files folder. I can't tell if the CPP file is being run, not exporting files, or exporting them somewhere else?
Please let me know if you any suggestions on compiling, calling cpp programs, or the system2 function. I've also heard about the sys and processx packages, so not sure if there is a better way to call system files that perhaps works across operating systems?
Thank you so much for your help!!
The documentation for system2 gives us two pieces of information:
We need to specify the command to be executed and the args as separate arguments.
By default, the return value of system2 is invisible, and it’s the status code of the command we executed.
The second point is the reason you’re not seeing any output.1 The first point is the reason why it doesn’t work in the first place: you need to specify the command and its arguments separately (and the arguments need to be a vector):
system2('./exe/socialrank', c('./files/summary_stats.txt', './files/network'))
This assumes that exe and files are subdirectories of the current working directory (and that the respective files exist in these locations).
In your case, the same command works for macOS, Windows and Linux.
Anyway, this is not quite the same as the example given in the usage guidance:
./socialrank summary_stats.txt graphname > debug.log
… because in the command above, output isn’t stored in a debug.log file but sent to the R console. This is very rarely useful. It’s much more common that you want to store the output itself in a variable in R. You can do that by adding the argument stdout = TRUE to the system2 call. Alternatively, specify stdout = 'debug.log' to do the same as the command above, i.e. store the output in a file.
1 Actually, on my system I still get a message: “[…] command not found”.
I intend to run some R Animation demo code but this error message returns
Warning messages:
1: In im.convert(img.files, output = movie.name, convert = convert, :
Please install ImageMagick first or put its bin path into the system PATH variable
I've downloaded ImageMagic for mac. It's a folder with subfolders like bin, lib, share etc. How can put its bin path into system path? Thanks.
Option 1:
Put something like
PATH=$PATH:blablabla/ImageMagic/bin
in ~/.bashrc file.
$PATH is the original PATH variable;
: is used to separate different candidates;
the final blablabla/ImageMagic/bin denotes the path to the executable.
Whenever you open up a new terminal, ~/.bashrc file will be run, hence environmental variable PATH will be set as above. If you start up your R from terminal, this should do the work.
Option 2:
If you normally invoke R by clicking its icon, then ~/.bashrc may not work. In this case, use the ~/.profile file instead. This is run whenever you log in. Add the following to the bottom of this file:
export PATH=$PATH:blablabla/ImageMagic/bin
(Note export here. You may need to log out and log in again so that the setting takes effect.)
Comments
Both ~/.bashrc and ~/.profile are hidden files. You may use ls -a ~ to see them. To edit/save them, use the normal text editor.
The link #Gregor gives, suggests using ~/.bash_profile. Well, These days this file is normally replaced by ~/.profile. But you should use ls -a ~ to check.
follow up:
OK, so you have .bash_profile instead of .profile on your machine.
To open this file, do:
sudo nano ~/.bash_profile
Then move to the bottom, and add the line you need:
export PATH=$PATH:blablabla/ImageMagic/bin
To save edit, do ctrl + O (maybe hitting an ENTER as well); then you quit editor by ctrl + X.
If you do not want to log out and log in again to let new setting take effect, try:
source ~/.bash_profile
I had the same problem with Windows a few weeks ago. I don't know if it is the same on Mac or not, but it is worth a try.
When you go to download ImageMagick there should be a prompt that says something like "select additional tasks." Be sure to check "Install Legacy Utilities (e.g. convert)." I think they changed the names of a few things between versions. That selection names things properly for R. Also, if this happens to be the same issue I had (maybe, maybe not) be sure to restart R before trying again after you've downloaded it.
.RData files are starting to invade my directory structure. I would like to retain a single one in a specified directory. Is there such an ENV variable similar to R_HISTFILE?
This is in reference to the default save/restore directory for R workspaces.
UPDATE The answer by JThorpe led to the following solution:
set Env var RPROFILE_USER to a desired location . I am using my home dir
i.e.:
export RPROFILE_USER=/Users/steve
In that directory create a file with setwd (set working directory)
i.e:
$cat ~/.Rprofile
setwd('/Users/steve')
Now the .RData will always load/save to the home dir (or whatever dir you put in setwd)
I personally dislike having R retain anything between sessions b/c it makes for difficult to find errors owing to variables that persist between sessions. Hence I set the “no-save” and “no-restore” options so that R neither writes its current state to an .Rdata file nor attempts to read in an old state. If I do happen to want to save an R session (this happens VERY rarely) I call savehistory().
Methods for setting command line options in OSX can be found here, and what follows describes setting command line options for R (or any other program) in windows.
To set the no-save and no-restore options in Windows, right-click on the R icon that you use to start an R session and select the ‘properties’ option. In the properties box, the “target” string should look something like this:
“C:\Program Files\R\R-3.1.2\bin\i386\Rgui.exe”
To this string, add this string ‘ --no-save --no-restore’. Note that there is a space before each of the double-dashes. The target should now look something like this:
“C:\Program Files\R\R-3.1.2\bin\i386\Rgui.exe” --no-save --no-restore
Click ‘Ok’ or ‘Apply’ to save these options. Note that these are per-icon (shortcut) settings. I have several icons with different command line options depending on the setting I want in the R session. Additional command line arguments to R can be found here.
Try the Load command in the Hmisc package. It uses the LoadPath option for this.
If you create a .Rprofile file you can specify a default working directory. See ?Startup for more details including the ability to set a site-wide profile. I just referred to that help page to make sure the .RData would be affected by that setting.
How can a sourced or Sweaved file find out its own path?
Background:
I work a lot with .R scripts or .Rnw files.
My projects are organized in a directory structure, but the path of the project's base directory frequently varies between different computers (e.g. because I just do parts of data analysis for someone else, and their directory structure is different from mine: I have projects base directories ~/Projects/StudentName/ or ~/Projects/Studentname/Projectname and most students who have just their one Project usually have it under ~/Measurements/ or ~/DataAnalysis/ or something the like - which wouldn't work for me).
So a line like
setwd (my.own.path ())
would be incredibly useful as it would allow to ensure the working directory is the base path of the project regardless of where that project actually is. Without the need that the user must think of setting the working directory.
Let me clarify: I look for a solution that works with pressing the editor's/IDE's source or Sweave Keyboard shortcut of the unthinking user.
Just FYI, knitr will setwd() to the dir of the input file when (and only when) evaluating the code chunks, i.e. if you call knit('path/to/input.Rnw'), the working dir will be temporarily switched to path/to/. If you want to know the input dir in code chunks, currently you can call an unexported function knitr:::input_dir() (I may export it in the future).
Starting from gsk3's Seb's suggestions, here's an idea:
the combination of username (login) and IP or name of the computer could be used to select the right directory.
That leads to something like:
setwd (switch (paste (Sys.info () [c ("user", "nodename")], collapse="."),
user.laptop = "~/Messungen",
user2.server = "~/Projekte/Projekt/",
))
So there is an automatic solution, that
works with source
works with Sweave
even works for interactive sessions where the commands are sent line by line
the combination of user and nodename of course needs to be specific
the paths need to be edited by hand, though.
Improvements welcome!
Update:
Gabor Grothendieck answered the following to a related question on r-help today:
this.dir <- dirname(parent.frame(2)$ofile)
setwd(this.dir)
which will work for source.
Another update: I now do most of the data analysis work in RStudio. RStudio's projects basically solve the problem: RStudio changes the working directory to the project root directory every time I switch between projects.
I can therefore put the project directory as far down my directory tree as I want (and the students can also put their copy wherever they want) and sync the data files and scripts/.Rnws via version control (We use a private git server). The RStudio project files are kept out of the version control, i.e. .gitignore contains .Rproj.user.
Obviously, within the project, the directory structure needs to be synchronized.
You can use sys.calls() to get the command used to source the file. Then you need a bit of trickery using regular expressions to get the pathname, bearing in mind that source("something/filename") could have used either the absolute or relative path. Here's a first attempt at putting all the pieces together: try inserting the following lines at the top of a source file.
whereFrom=sys.calls()[[1]]
# This should be an expression that looks something like
# source("pathname/myfilename.R")
whereFrom=as.character(whereFrom[2]) # get the pathname/filename
whereFrom=paste(getwd(),whereFrom,sep="/") # prefix it with the current working directory
pathnameIndex=gregexpr(".*/",whereFrom) # we want the string up to the final '/'
pathnameLength=attr(pathnameIndex[[1]],"match.length")
whereFrom=substr(whereFrom,1,pathnameLength-1)
print(whereFrom) # or "setwd(whereFrom)" to set the working directory
It's not very robust—for instance, it will fail on windows with source("pathname\\filename"), and I haven't tested what happens if you have one file sourcing another file—but you might be able to build a solution on top of this.
I have no direct solution how to obtain the directory of the file itself but if you have a limited range of directories and directory structures you can probably use
if(file.exists("c:/somedir")==TRUE){setwd("c:/somedir")}
You could check out the pattern of the directory in question and then set the dir. Does this help you?
An additional problem is that the working directory is a global variable, which can be changed by any script, so if your script calls another script, it will have to set the wd back. In RStudio I use Session -> Set Working Directory -> To Source File Location (I know, it's not ideal), and then my script does
wd = getwd ()
...
source ("mySubDir/myOtherScript.R", chdir=TRUE); setwd (wd)
...
source ("anotherSubDir/anotherScript.R", chdir=TRUE); setwd (wd)
In this way one can maintain a stack of working directories. I would love to see this implemented in the language itself.
This answer works for source and also inside nvim-R - I have no idea if it works with knitr and similar things. Any feedback appreciated.
If you have multiple scripts source-ing each other, it is important to get the correct one. That is, the largest i for which sys.frame(i)$ofile exists.
get.full.path.to.this.sourced.script = function() {
for(i in sys.nframe():1) { # Go through all the call frames,
# in *reverse* order.
x = sys.frame(i)$ofile
if(!is.null(x)) # if $ofile exists,
return(normalizePath(x)) # then return the full absolute path
}
}