Home > Enterprise >  Heatmaps with eye-tracking data (weighted 2D-density)
Heatmaps with eye-tracking data (weighted 2D-density)

Time:04-23

I am trying to create a fixation maps where the weight of each fixation on the 2d density map is determined by its duration. As I understood, the stat_density2d() function accepts the weight argument but does not process it (enter image description here

CodePudding user response:

Not a ggplot2 user, but basically you want to estimate a weighted 2d-density and make an image out of it. Your enter image description here

This almost runs forever, though with n=1000...

Weighted 2d density estimation

In a comment on the answer mentioned above, enter image description here

However, the two versions look quite different, and I can't tell which is right, since I am not really an expert with this method. But at least there is a noticeable difference to the unweighted image:

Unweighted image

dens0 <- MASS::kde2d(df$x, df$y, n=n)
image(dens0, col=heat.colors(n, rev=TRUE))

enter image description here

Points

Still adding the points might be pointless, but you could run this line after image:

points(y ~ x, df, cex=proportions(dur)*2e3, col='green')

Taken from r-help (Ort 2006):

kde2d.weighted <- function(x, y, w, h, n=n, lims=c(range(x), range(y))) {
  nx <- length(x)
  if (length(y) != nx) 
    stop("data vectors must be the same length")
  gx <- seq(lims[1], lims[2], length=n)  ## gridpoints x
  gy <- seq(lims[3], lims[4], length=n)  ## gridpoints y
  if (missing(h)) 
    h <- c(MASS::bandwidth.nrd(x), MASS::bandwidth.nrd(y))
  if (missing(w)) 
    w <- numeric(nx)   1
  h <- h/4
  ax <- outer(gx, x, "-")/h[1]  ## distance of each point to each grid point in x-direction
  ay <- outer(gy, y, "-")/h[2]  ## distance of each point to each grid point in y-direction
  z <- (matrix(rep(w,n), nrow=n, ncol=nx, byrow=TRUE)*
          matrix(dnorm(ax), n, nx)) %*% 
    t(matrix(dnorm(ay), n, nx))/(sum(w)*h[1]*h[2])  ## z is the density
  return(list(x=gx, y=gy, z=z))
}

CodePudding user response:

The simplest way round this is to use tidyr::uncount to replicate the rows of your data frame, using dur as weights:

library(ggplot2)

ggplot(tidyr::uncount(df, dur), aes(x=x, y =y))  
  stat_density2d(geom='raster', 
                 aes(fill=..count.., alpha=..count..), contour=FALSE)   
  geom_point(data = df, aes(size=dur), alpha=0.2, color="red")  
  scale_fill_gradient(low="green", high="red")  
  scale_alpha_continuous(range=c(0, 1) , guide="none")  
  theme_void()

enter image description here

The effect is probably easier to see with the points removed:

ggplot(tidyr::uncount(df, dur), aes(x=x, y =y))  
  stat_density2d(geom='raster', 
                 aes(fill=..count.., alpha=..count..), contour=FALSE)   
  scale_fill_gradient(low="green", high="red")  
  scale_alpha_continuous(range=c(0, 1) , guide="none")  
  theme_void()

enter image description here

  • Related