在JavaScript中检索R对象属性 - 第2部分 [英] Retrieving R object attributes in JavaScript - Part 2

查看:103
本文介绍了在JavaScript中检索R对象属性 - 第2部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我之前发布了一个类似的问题(



例如,如果我点击绿色框中突出显示的六边形,我可以确定它出现在哪个子图(myX和myY),点击的六边形的ID(hexID),以及分组到该六边形中的观察点的数量(计数)。对于这个特殊的六边形,myX = 5,myY = 2,hexID = 39,count = 1。因此,用户只是在第五行和第二列的散点图中点击了带有ID39的六边形,并且应该有一个数据点被分箱。



如果我离开onRender()函数,只需在R中键入以下代码:

  myX<  -  5 
myY< - 2
hexID< - 39
obsns< - 其中(attr(pS [myX,myY] $ data,cID)== hexID)
dat< - bindata [ [b
>

然后,我可以获得包含一个装入单击的六边形:

 > dat 
ID ABCDE
95 ID95 1.586833 -1.208083 1.778429 -0.1101588 3.810277

My问题只是在最后一步。我无法弄清楚如何在onRender()函数中使用base :: attr()函数来获取obsns对象。是否有针对此问题的解决方法,或者我应考虑采取的其他可行方法?感谢您的任何想法/建议!

解决方案

我不确定您是否可以从 plotly 或者它是否将这些数据保存在某个位置,因此一个选项是将所需的所有数据传递给 onRender 函数。



首先,你可以在每个hexplot中添加一个列 bindata 数据帧,名为 mX-mY (其中你用每个列的值替换mX和mY),这将为每个观察保留它所属的那个hexbin:

  for(i in 2:5){
for(j in 1:4){
bindata [[paste(i,j,sep = - )) ]]< - attr(pS [i,j] $ data,cID)
}
}

然后你可以将 bindata 传递给 onRender 函数,并且当你点击一个其中一个图中的六边形,检查 bindata 中的相应列,哪些观察属于该六边形:

  ggPS%>%onRender(
函数(el,x,data){

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


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)


I posted a similar question earlier (Retrieving R object attributes in JavaScript). In that earlier post, I oversimplified my MWE, and so the answer I rewarded unfortunately does not really apply to my real problem. Here, I am showing why I may need to retrieve R object attributes in JavaScript (unless there is another option that I am not aware of).

I have a 5-variable dataset with 100 observations. I used hexagon binning and created a scatterplot matrix. Each of the 10 scatterplots has somewhere between 12-18 hexagons. In order to save the rows of the 100 observations that are in each of the hexagon bins for all 10 scatterplots, I used the base::attr function in R. In the code below, this is done at:

attr(hexdf, "cID") <- h@cID

I am trying to create an interactive R Plotly object of the hexagon binning so that if a user were to click on a given hexagon bin (regardless of which scatterplot), they would obtain the rows of the 100 observations that were grouped into that bin. I have part of this goal completed. My MWE is below:

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 = h@cell, counts = h@count)
  attr(hexdf, "cID") <- h@cID
  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)

This creates an image as shown below:

As an example, if I click on the hexagon highlighted in the green box, I can determine which subplot it occurred in ("myX" and "myY"), the ID of the hexagon clicked ("hexID"), and the number of observation points that were binned into that hexagon ("counts"). For this particular hexagon, myX=5, myY=2, hexID=39, and counts=1. So, the user just clicked on hexagon with ID39 in the scatterplot on the fifth row and second column and there should be 1 data point that it binned.

If I leave the onRender() function, and simply type into R the following code:

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

Then, I can obtain the row of the data frame that contains the one observation that was binned into that clicked hexagon:

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

My problem is simply in this last step. I am unable to figure out how to use the base::attr() function from within the onRender() function in order to obtain the "obsns" object. Is there any workaround for this issue, or another possible approach I should consider taking? Thank you for any ideas/advice!

解决方案

I'm not sure you can access the hex IDs from plotly or whether it keeps this data somewhere so one option is to pass all the data needed for your purpose to the onRender function.

First you could add to your bindata dataframe a column per hexplot, called mX-mY (where you replace mX and mY by their value for each column), that would hold for each observation the hexbin it belongs to for that plot:

for(i in 2:5) {
  for(j in 1:4) {
    bindata[[paste(i,j,sep="-")]] <- attr(pS[i,j]$data, "cID")
  }
}

You can then pass bindata to the onRender function and whever you click on a hexagon in one of the plot, check in the corresponding column in bindata which observations belong to that hexbin:

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)

这篇关于在JavaScript中检索R对象属性 - 第2部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆