2017-02-25 6 views
4

私は以前同様の質問を投稿しました(Retrieving R object attributes in JavaScript)。その前の記事では、私はMWEを単純化したので、残念なことに報われた答えは私の本当の問題にはあてはまらない。ここでは、JavaScriptでRオブジェクトの属性を取得する必要がある理由を示しています(私が気づいていない別のオプションがない限り)。JavaScriptでRオブジェクトの属性を取得する - パート2

私は100の観測値を持つ5変数データセットを持っています。私は六角形ビニングを使用し、散布図マトリックスを作成しました。 10個の散布図のそれぞれは、12-18六角形の間のどこかにあります。

attr(hexdf, "cID") <- [email protected] 
:全10回の散布用六角ビンのそれぞれにある100個の観測値の列を保存するために、私はベース::以下のコードでR.でATTR関数を用い、これはで行われます

私は六角形ビニングのインタラクティブなR Plotlyオブジェクトを作成しようとしています。そのため、ユーザーが任意の六角形のビンをクリックすると(その散布図に関係なく)、そのビンにグループ化された100個の観測の行を取得します。私はこの目標の一部を完成させました。私のMWEは以下の通りです:

library(plotly) 
library(data.table) 
library(GGally) 
library(hexbin) 
library(htmlwidgets) 

set.seed(1) 
bindata <- data.frame(ID = paste0("ID",1:100), A=rnorm(100), B=rnorm(100), C=rnorm(100), D=rnorm(100), E=rnorm(100)) 
bindata$ID <- as.character(bindata$ID) 

maxVal = max(abs(bindata[,2:6])) 
maxRange = c(-1*maxVal, maxVal) 

my_fn <- function(data, mapping, ...){ 
    x = data[,c(as.character(mapping$x))] 
    y = data[,c(as.character(mapping$y))] 
    h <- hexbin(x=x, y=y, xbins=5, shape=1, IDs=TRUE, xbnds=maxRange, ybnds=maxRange) 
    hexdf <- data.frame (hcell2xy (h), hexID = [email protected], counts = [email protected]) 
    attr(hexdf, "cID") <- [email protected] 
    p <- ggplot(hexdf, aes(x=x, y=y, fill = counts, hexID=hexID)) + geom_hex(stat="identity") 
    p 
} 

p <- ggpairs(bindata[,2:6], lower = list(continuous = my_fn)) 
pS <- p 
for(i in 2:p$nrow) { 
    for(j in 1:(i-1)) { 
    pS[i,j] <- p[i,j] + 
     coord_cartesian(xlim = c(maxRange[1], maxRange[2]), ylim = c(maxRange[1], maxRange[2])) 
    } 
} 

ggPS <- ggplotly(pS) 

myLength <- length(ggPS[["x"]][["data"]]) 
for (i in 1:myLength){ 
    item =ggPS[["x"]][["data"]][[i]]$text[1] 
    if (!is.null(item)) 
    if (!startsWith(item, "co")){ 
     ggPS[["x"]][["data"]][[i]]$hoverinfo <- "none" 
    } 
} 

ggPS %>% onRender(" 
      function(el, x, data) { 
      el = el; 
      x=x; 
      var data = data[0]; 
      console.log(el) 
      console.log(x) 
      console.log(data) 

      myLength = Math.sqrt(document.getElementsByClassName('cartesianlayer')[0].childNodes.length); 
      console.log(myLength) 

      el.on('plotly_click', function(e) { 
      console.log(e.points[0]) 
      xVar = (e.points[0].xaxis._id).replace(/[^0-9]/g,'') 
      if (xVar.length == 0) xVar = 1 
      yVar = (e.points[0].yaxis._id).replace(/[^0-9]/g,'') 
      if (yVar.length == 0) yVar = 1 
      myX = myLength + 1 - (yVar - myLength * (xVar - 1)) 
      myY = xVar 

      cN = e.points[0].curveNumber 
      split1 = (x.data[cN].text).split(' ') 
      hexID = (x.data[cN].text).split(' ')[2] 
      counts = split1[1].split('<')[0] 

      console.log(myX) 
      console.log(myY) 
      console.log(hexID) 
      console.log(counts) 
      })} 
      ", data = pS[5,2]$data) 

以下に示すように、このイメージを作成します。例として

Scatterplot matrix of hexagon binning

を、私は六角をクリックすると緑色のボックスで強調表示、私はどのサブプロットを決定することができます(「myX」と「myY」)、クリックされた六角形のID(「hexID」)、およびその六角形にビニングされた観測点の数(「カウント」)で発生しました。この特定の六角形の場合、myX = 5、myY = 2、hexID = 39、およびcounts = 1です。したがって、ユーザーは、5行目と2列目の散布図にあるID39の六角形をクリックしただけで、1つのデータポイントが格納されるはずです。

IはonRender()関数を残して、単にRに次のコードを入力した場合:次に

myX <- 5 
myY <- 2 
hexID <- 39 
obsns <- which(attr(pS[myX,myY]$data, "cID")==hexID) 
dat <- bindata[obsns,] 

を、私はそれにビニングされた一回の観察を含むデータフレームの列を取得することができますクリックした六角:

> dat 
    ID  A   B  C   D  E 
95 ID95 1.586833 -1.208083 1.778429 -0.1101588 3.810277 

私の問題はこの最後のステップです。 "obsns"オブジェクトを取得するためにonRender()関数内からbase :: attr()関数を使用する方法を理解できません。この問題の回避策がありますか?または別の取り組みを検討する必要がありますか?アイデア/アドバイスありがとう!

答えて

1

plotlyから16進IDにアクセスできるかどうか、またはこのデータをどこかに保持するかどうかわからないため、目的に必要なすべてのデータをonRender関数に渡すことが1つの方法です。各観測のために、それはそのプロットの属するhexbinを開催する

まず、あなたのbindataデータフレームにhexplotあたりの列を追加することができ、mX-mYと呼ばれる(あなたが各列のその値によってMXを交換し、私の場合)、:

for(i in 2:5) { 
    for(j in 1:4) { 
    bindata[[paste(i,j,sep="-")]] <- attr(pS[i,j]$data, "cID") 
    } 
} 
あなたはその後、 onRender関数に bindataを渡すことができますし、wheverあなたがそのhexbinに属する観測 bindataに対応する欄にチェックし、プロットの一つに、六角形をクリックしてください

ggPS %>% onRender(" 
       function(el, x, data) { 

       myLength = Math.sqrt(document.getElementsByClassName('cartesianlayer')[0].childNodes.length); 


       el.on('plotly_click', function(e) { 
       xVar = (e.points[0].xaxis._id).replace(/[^0-9]/g,'') 
       if (xVar.length == 0) xVar = 1 
       yVar = (e.points[0].yaxis._id).replace(/[^0-9]/g,'') 
       if (yVar.length == 0) yVar = 1 
       myX = myLength + 1 - (yVar - myLength * (xVar - 1)) 
       myY = xVar 

       cN = e.points[0].curveNumber 
       split1 = (x.data[cN].text).split(' ') 
       hexID = (x.data[cN].text).split(' ')[2] 
       counts = split1[1].split('<')[0] 

       var selected_rows = []; 

       data.forEach(function(row){ 
       if(row[myX+'-'+myY]==hexID) selected_rows.push(row); 
       }); 
       console.log(selected_rows); 

       })} 
       ", data = bindata) 
+0

これを私に指摘していただきありがとうございます。私は長い間このことに取り組んできました。あなたが以前に1つのサブプロットでそれを示した後でさえ、attr()を使用することはできませんでした。私にとって驚くべきことは、このアプローチがonRender()関数の遅延を引き起こさないように見えるということです。データフレームのサイズを100から50,000に変更しました。与えられた六角形をクリックすると、その大きなデータフレームを直ちに解析して50,000のデータフレームを取得し、個々の観測値を取得することができます。私はJavaScriptが、これが私が予想していたより速く起こることを許していると思います(私は主にRを使います)? – luckButtered

関連する問題