5

gWidgetsを使用してRでGUIを作成しています。今まで私は地球環境を介してあるウィンドウから別のウィンドウに値を渡していました。地球環境を使用するのは簡単ですが理想的ではありません。 1つの問題は、R CMD checkがグローバル変数の目に見えるバインディングを欠いていると言うことです。R参照クラスを使用してGUI内のあるウィンドウから別のウィンドウに値を渡す

参照クラスは、いくつかのRプログラマによって言及されている。しかし、この文脈で参照クラスがどのように機能するかを理解するためには、単純な例を持つことが本当に役に立ちます。

私はうまくGUIを使って作業しましょう。ユーザーが最初のウィンドウのボタンを押すと、モデルmがグローバル環境に置かれます。 2番目のボタンは地球環境からmを得て、出力を出します。最初のボタンをもう一度押すと、新しいモデルmが作成され、2番目のボタンの出力が変更されます。最初のウィンドウを閉じると、mがグローバル環境にあるため、2番目のウィンドウのボタンは引き続き機能します。

library(gWidgets) 
options(guiToolkit = "tcltk") 

h1 <- function(h, ...){ 
    d1 <- data.frame(x=runif(10), y=runif(10)) 
    .GlobalEnv$m <- lm(x ~ y, data=d1) 
} 

g1 <- gbutton("1. Make model", 
    container=gwindow(), handler=h1) 

h2 <- function(h, ...){ 
    d2 <- data.frame(y=(1:10)/10) 
    p <- predict(.GlobalEnv$m, newdata=d2) 
    print(p) 
} 

g2 <- gbutton("2. Make prediction", 
    container=gwindow(), handler=h2) 

この例では、どのように参照クラスを使用できますか?

答えて

2

setRefClassと呼び出し、各ウィジェットとデータ値をフィールドとして含めます。ウィジェットのタイプはANYである必要があります。 initializeメソッドでこれらのウィジェットを初期化し、機能を他のメソッドに委譲します。クラスの作成をラップする関数を作成します。

silly_gui_generator <- setRefClass(
    "SillyGui", 
    fields = list(
    #widgets 
    win1   = "ANY", 
    win2   = "ANY", 
    button1  = "ANY", 
    button2  = "ANY", 
    #data 
    modelData  = "data.frame", 
    predictionData = "data.frame", 
    model   = "lm" 
), 
    methods = list(
    initialize = function(modelData = NULL) 
    { 
     if(is.null(modelData)) 
     { 
     modelData <<- data.frame(x = runif(10), y = runif(10)) 
     } 

     win1 <<- gwindow(visible = FALSE) 
     win2 <<- gwindow(visible = FALSE) 
     button1 <<- gbutton(
     "1. Make model", 
     container = win1, 
     handler = function(h, ...) 
     {   
      makeModel() 
     } 
    ) 
     button2 <<- gbutton(
     "2. Make prediction", 
     container = win2, 
     handler = function(h, ...) 
     {   
      print(predictModel()) 
     } 
    ) 
     visible(win1) <- TRUE 
     visible(win2) <- TRUE 
    }, 
    makeModel = function() 
    { 
     model <<- lm(x ~ y, data = modelData) 
    }, 
    predictModel = function() 
    { 
     predictionData <<- data.frame(y = (1:10)/10) 
     predict(model, newdata = predictionData) 
    } 
) 
) 

generate_silly_gui <- function(modelData = NULL) 
{ 
    invisible(silly_gui_generator$new(modelData = modelData)) 
} 
+0

素晴らしい例です。このコードは警告を出します:.checkFieldsInMethod(def、fieldNames、allMethods): フィールド名へのローカル割り当ては、フィールドを変更しません: modelData < - data.frame(x = runif(10)、y = runif(10) );可視(win1)< - TRUE; visible(win2)< - TRUE "<< - "を使用しましたか? (メソッド "SillyGui"クラスの "初期化") – JacobVanEtten

+1

@JacobVanEttenありがとう。私は 'modelData < - '行を修正しました。 '目に見える<--'行はローカル割り当てでなければなりません。 'suppressWarnings'の中の' setRefClass'に呼び出しをラップしてください。 –

+0

ありがとう!私はJohn'sの提案を最初に従いますが、この例をオンラインにすることは素晴らしいことです。 – JacobVanEtten

2

リッチーの答えはそれを行う方法の1つです。これは、単一のオブジェクトを返します(generate_silly_guiによって返されたインスタンスは、のGUIを使用するウィジェットを操作するのに使用できます)良いアプローチ。以下は、モデルを実行するだけで、問題のコードからここに参照クラスの使用は環境を使用して、より構造化された方法である:。

OurModel <- setRefClass("OurModel", 
         fields="m") 

## a global 
model_instance = OurModel$new(m=NULL) 

それからちょうどあなたのコードと実行にmodel_instance$m.GlobalEnv$mを置き換える

をクラスができます参照を使用しました。あなたはゲッターとセッターを追加するようなことをやって、他のことをやって、モードに向かってあなたをプッシュしますl-view-controllerスタイルです。 objectSignalsパッケージはその方向に向いています。

GUIが複雑になる場合は、2つの方法を切り離したい場合があります。

+0

素晴らしい例ですが、これを最初に試してみて、 'objectSignals'を見てみましょう。このアプローチを使用すると、 'R CMD CHECK'は目に見えるバインディングについて不平を言うことはありませんか? – JacobVanEtten

+0

ちょっと試しました。私はパッケージの.onLoad関数で参照クラスのインスタンスを作成し、それをパッケージの関数の内部で使用します。これはまだグローバルバインディングの問題を引き起こします...これを避けるためにもちろん汚いトリックがあります:[リンク](http://stackoverflow.com/questions/8096313/no-visible-binding-for-global-variable-note- in-r-cmd-check)を実行します。しかし、私は参照クラスがこれを不要にすると思った... – JacobVanEtten

+0

コード内にインスタンスを作成することができます。たとえば、https://github.com/jverzani/gWidgets2RGtk2/blob/master/R/icons.R#L106 – jverzani

関連する問題