source
dまたはSweave
dファイルはどのようにして独自のパスを見つけることができますか?
バックグラウンド:
私は.Rスクリプトまたは.Rnwファイルをよく扱います。私のプロジェクトはディレクトリ構造で構成されていますが、プロジェクトのベースディレクトリのパスは、コンピュータごとに異なることがよくあります(たとえば、他の人のためにデータ分析の一部を実行するだけで、ディレクトリ構造が私のものとは異なるためです。プロジェクトのベースディレクトリがあります。 〜/ Projects/StudentName /または〜/ Projects/Studentname/Projectnameと、プロジェクトが1つしかないほとんどの学生は、通常、〜/ Measurements /または〜/ DataAnalysis /などの下にプロジェクトを持っています-これは私には機能しません)。
だから次のような行
setwd (my.own.path ())
プロジェクトが実際にどこにあるかに関係なく、作業ディレクトリがプロジェクトのベースパスであることを確認できるため、非常に便利です。ユーザーが作業ディレクトリの設定を考える必要はありません。
明確にしましょう。私は、エディター/ IDEのsource
またはSweave
キーボードショートカットを思いもよらないユーザーに押して動作するソリューションを探しています。
参考までに、コードチャンクを評価するとき(そしてそのときだけ)、つまりsetwd()
を呼び出すと、作業ディレクトリにknitr
が入力ファイルのディレクトリにknit('path/to/input.Rnw')
します。一時的に_path/to/
_に切り替えられます。コードチャンクの入力ディレクトリを知りたい場合は、現在、エクスポートされていない関数knitr:::input_dir()
を呼び出すことができます(将来エクスポートする可能性があります)。
Gsk3のSebの提案から始めて、ここにアイデアがあります:
それは次のようなものにつながります:
setwd (switch (paste (Sys.info () [c ("user", "nodename")], collapse="."),
user.laptop = "~/Messungen",
user2.server = "~/Projekte/Projekt/",
))
つまり、自動ソリューションがあります。
source
で動作しますSweave
で動作しますコマンドが1行ずつ送信されるインタラクティブセッションでも機能します
もちろん、user
とnodename
の組み合わせは具体的である必要があります
改善を歓迎します!
更新:
Gabor Grothendieckは、今日のr-helpに関する関連する質問に次のように答えました。
this.dir <- dirname(parent.frame(2)$ofile)
setwd(this.dir)
これはsource
で機能します。
別の更新:私は現在、RStudioでほとんどのデータ分析作業を行っています。 RStudioのプロジェクトは基本的に問題を解決します。RStudioは、プロジェクトを切り替えるたびに、作業ディレクトリをプロジェクトルートディレクトリに変更します。
したがって、プロジェクトディレクトリをディレクトリツリーの最下位に配置し(学生はコピーを好きな場所に配置することもできます)、バージョン管理を介してデータファイルとスクリプト/ .Rnw
sを同期できます(プライベートを使用します) gitサーバー)。 RStudioプロジェクトファイルはバージョン管理の対象外になります。つまり、.gitignore
には.Rproj.user
が含まれます。
明らかに、withinプロジェクトでは、ディレクトリ構造を同期する必要があります。
sys.calls()
を使用して、ファイルのソースに使用されるコマンドを取得できます。次に、source("something/filename")
が絶対パスまたは相対パスのいずれかを使用する可能性があることを念頭に置いて、正規表現を使用してパス名を取得するためのちょっとした工夫が必要です。これがすべての部分をまとめる最初の試みです:ソースファイルの先頭に次の行を挿入してみてください。
_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
_
それほど堅牢ではありません。たとえば、source("pathname\\filename")
のあるウィンドウでは失敗します。あるファイルが別のファイルを調達している場合にどうなるかはテストしていませんが、その上にソリューションを構築できる可能性があります。これの。
ファイル自体のディレクトリを取得する直接的な解決策はありませんが、ディレクトリとディレクトリ構造の範囲が限られている場合は、おそらく使用できます
if(file.exists("c:/somedir")==TRUE){setwd("c:/somedir")}
問題のディレクトリのパターンを確認してから、ディレクトリを設定できます。これはあなたを助けますか?
追加の問題は、作業ディレクトリがグローバル変数であり、任意のスクリプトで変更できるため、スクリプトが別のスクリプトを呼び出す場合は、wdを元に戻す必要があることです。 RStudioでは、[セッション]-> [作業ディレクトリの設定]-> [ソースファイルの場所へ]を使用します(これは理想的ではありません)。
wd = getwd ()
...
source ("mySubDir/myOtherScript.R", chdir=TRUE); setwd (wd)
...
source ("anotherSubDir/anotherScript.R", chdir=TRUE); setwd (wd)
このようにして、作業ディレクトリのスタックを維持できます。これが言語自体で実装されることを望んでいます。
この回答はsource
でも機能し、_nvim-R
_内でも機能します-knitr
などで機能するかどうかはわかりません。フィードバックをいただければ幸いです。
複数のスクリプトが互いにsource
-している場合は、正しいスクリプトを取得することが重要です。つまり、sys.frame(i)$ofile
が存在する最大のi
です。
_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
}
}
_