I have a bivariate dataset with 100 observations. I used hexagon binning and ended up with 26 hexagon bins. In order to save the rows of the 100 observations that are in each of the 26 hexagon bins, 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, 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))
bindata$ID <- as.character(bindata$ID)
x = bindata[,c("A")]
y = bindata[,c("B")]
h <- hexbin(x=x, y=y, xbins=5, shape=1, IDs=TRUE)
hexdf <- data.frame (hcell2xy (h), hexID = h@cell, counts = h@count)
attr(hexdf, "cID") <- h@cID
pS <- ggplot(hexdf, aes(x=x, y=y, fill = counts, hexID=hexID)) + geom_hex(stat="identity")
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) {
//console.log(el)
//console.log(x)
//console.log(data)
myGraph = document.getElementById(el.id);
el.on('plotly_click', function(e) {
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(hexID)
console.log(counts)
})}
", data = pS$data)
When I run this code and open it in the Web Browser, I obtain an interactive plot like below (green box is not in plot; it's superimposed for explanatory purposes):
If I click on the hexagon inside the green box, the correct hexID
of 40 and counts
of 3 are printed to the console. At this point, I would like to obtain the 3 rows of the original data frame that were put into that hexagon bin.
I know how to do this in R outside of the onRender()
function of the htmlwidgets
package by using the base::attr
function. For instance, I can do the following:
hexID=40
obsns <- which(attr(pS$data, "cID")==hexID)
dat <- bindata[obsns,]
And receive the following correct 3 data points that were put into that bin I clicked on:
ID A B
47 ID47 0.3645820 2.087167
66 ID66 0.1887923 2.206102
71 ID71 0.4755095 2.307978
I am working with much larger datasets than in this MWE. For that reason, my intention of using the base:attr
function was to prevent ever larger data frame floating around. However, I am unsure how to translate the functionality of the base::attr
function so that I can access the appropriate data point rows that occur in a clicked hexagon bin in the onRender()
JavaScript code. I did include the pS$data
object into the onRender()
JavaScript code, but am still stuck.
Any advice would be sincerely appreciated!
You could add a column which for each row has the ID of the hexbin it belongs to in your bindata:
bindata$hex <- h@cID
You can then pass it to the onRender
function and filter rows when the users clicks on a hexagon:
ggPS %>% onRender("
function(el, x, data) {
myGraph = document.getElementById(el.id);
el.on('plotly_click', function(e) {
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.hex==hexID) selected_rows.push(row);
});
console.log(selected_rows);
})}
", data = bindata)