Получение атрибутов R объекта в JavaScript - Часть 2
Я опубликовал аналогичный вопрос ранее ( Получение атрибутов объекта R в JavaScript). В этом предыдущем посте я упростил свой MWE, и поэтому ответ, который я получил, к сожалению, на самом деле не относится к моей реальной проблеме. Здесь я показываю, почему мне может понадобиться получить атрибуты объекта R в JavaScript (если нет другой опции, о которой я не знаю).
У меня есть 5-переменный набор данных с 100 наблюдениями. Я использовал шестиугольник и создал матрицу рассеяния. Каждый из 10 графиков рассеяния имеет где-то между 12-18 шестиугольниками. Чтобы сохранить строки из 100 наблюдений, которые находятся в каждой из шестиугольных корзин для всех 10 диаграмм рассеяния, я использовал функцию base::attr в R. В приведенном ниже коде это делается в:
attr(hexdf, "cID") <- h@cID
Я пытаюсь создать интерактивный объект 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 = 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)
Это создает изображение, как показано ниже:
Например, если я нажму на шестиугольник, выделенный в зеленом поле, я могу определить, в каком подзаговоре он произошел ("myX" и "myY"), идентификатор шестнадцатеричного клика ("hexID") и номер точки наблюдения, которые были объединены в этот шестиугольник ("отсчеты"). Для этого конкретного шестиугольника myX=5, myY=2, hexID=39 и число =1. Таким образом, пользователь просто щелкнул шестиугольник с ID39 на диаграмме рассеяния в пятом ряду и втором столбце, и должна быть одна точка данных, которую он скомпоновал.
Если я оставлю функцию 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
Моя проблема просто в этом последнем шаге. Я не могу понять, как использовать функцию base::attr() из функции onRender() для получения объекта "obsns". Есть ли решение этой проблемы или другой возможный подход, который я должен рассмотреть? Спасибо за любые идеи / советы!
1 ответ
Я не уверен, что вы можете получить доступ к шестнадцатеричным идентификаторам из plotly
или хранит ли эти данные где-то, поэтому один из вариантов - передать все данные, необходимые для вашей цели, в onRender
функция.
Сначала вы можете добавить в свой bindata
Фрейм данных столбца на гексплот, называется mX-mY
(где вы заменяете mX и mY на их значение для каждого столбца), для каждого наблюдения будет храниться гексбин, которому он принадлежит для этого графика:
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("
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)