Here, we show how to compute the (PCF) for eye movement data in three steps. The PCF reveals whether the distribution of fixation locations during a single scanpath can be explained by the overall inhomogeneity observed across all observers or whether fixation locations of a single scanpath contain additional spatial correlations. For details we refer to our manuscript (Trukenbrod, Barthelmé, Wichmann, & Engbert, 2018).

library(tidyverse)
library(spatstat)
library(ggplot2)
library(parallel)

Data Set

For our analyses we use an experiment, where participants viewed two types of images twice. The repeated presentation of images allows to investigate the influence of visual long-term memory on eye movements. From previous work we expect that the repeated presentation leads to similar fixation densities but shortens saccade amplitudes during the second inspection. The resulting point patterns are similar but differ slightly in the overall inhomogeneity, which makes a direct comparison of the eye movement behavior difficult. The same problem is true for the comparison of different image types. The PCF takes differences in the underlying inhomogeneity into account and allows a direct comparison of the spatial correlations under different viewing conditions (first vs. second presentation) and for different image types (natural vs. texture images).

Our data set contains scanpaths from 35 participants viewing 30 images twice. Images were either natural scenes or images of texture images. The initial fixation, fixations containing blinks, and fixations outside the image boundaries were removed from further analyses. Overall 57344 fixations remained.

# image coordinates
xrange <- c(1.03585769369965,32.1115885046892)
yrange <- c(0.828686154959722,25.6892708037514)
dat <- read.table('./data/SpSt1.dat',header=TRUE)
d <- dat %>%
  mutate(.,xpos=(xR+xL)/2,ypos=(yR+yL)/2) %>% 
  filter(., nth>1 & blinkFix==0 & blinkSac==0 &
           xpos>xrange[1] & xpos<xrange[2] &
           ypos>yrange[1] & ypos<yrange[2]) %>%
  select(.,id,type,nthPres,image,xpos,ypos)
d$id <- factor(d$id)
d$type <- factor(d$type,levels=c(1,2),labels=c('Natural scene','Texture'))
d$nthPres <- factor(d$nthPres,levels=c(1,2),labels=c('First','Second'))
d$image <- factor(d$image)
summary(d)
       id                   type         nthPres          image            xpos             ypos       
 3      : 2545   Natural scene:29061   First :32201   10     : 2125   Min.   : 1.095   Min.   : 0.840  
 21     : 2077   Texture      :28283   Second:25143   8      : 2083   1st Qu.:11.350   1st Qu.: 9.815  
 28     : 2017                                        24     : 2012   Median :16.055   Median :14.005  
 12     : 2010                                        26     : 2007   Mean   :16.561   Mean   :13.705  
 23     : 1992                                        3      : 2001   3rd Qu.:21.995   3rd Qu.:17.765  
 8      : 1814                                        6      : 1997   Max.   :32.110   Max.   :25.670  
 (Other):44889                                        (Other):45119                                    

Step 1. Simulation of inhomogeneous and homogeneous control processes.

For our PCF computations, we need to simulate two control point processes, namely a homogeneous and an inhomogeneous point process. Points (fixation locations) are sampled independently from each other in both control processes and due to the independence of points, we do not expect to observe any spatial correlations between points at distance \(r\). Any observed correlations would be spurious and depend on the data structure (e.g., length of fixation sequences) or a wrong parameterization of the method. Hence, both control processes ensure that correlations in the PCF arise from the empirical data and not by the method itself. In addition, the inhomogeneous point process is used in the second step to estimate an optimal bandwidth for the intensity estimation of the PCF in Step 3.

For simulation of the control processes we need to pick a bandwidth for the estimation of the fixation density. Here, we use Scott’s rule of thumb (\(\tt bw.scott()\)). For each empirical scanpath we simulated one scanpath of equal length (same number of fixations as observed in the experiment) for the inhomogeneous point process and for the homogeneous point process. As a result we now have fixations from three point processes (PP) with the same number of fixations each.

sigma <- NULL
for (img in unique(d$image)){
  for (pres in unique(d$nthPres)){
    idx <- d$nthPres==pres & d$image==img
    dImg <- d[idx,]
    ppImg <- ppp(dImg$xpos,dImg$ypos,window=owin(xrange,yrange))
    bwImg <- mean(bw.scott(ppImg))
    sigma <- rbind(sigma,data.frame(img,pres,bwImg))
    denImg <- density(ppImg,sigma=bwImg)
    sim <- rpoint(nrow(dImg),denImg)
    d$xposInhom[idx] <- round(sim$x,digits=3)
    d$yposInhom[idx] <- round(sim$y,digits=3)
  }
}
sim <- rpoint(nrow(d))
d$xposHom <- round(sim$x*diff(xrange)+xrange[1],digits=3)
d$yposHom <- round(sim$y*diff(yrange)+yrange[1],digits=3)
dx <- gather(d,'pp','x',c(5,7,9))
dy <- gather(d,'pp','y',c(6,8,10))
d <- cbind(dx[,-c(5,6,7)],y=dy$y)
d$pp <- factor(d$pp,levels=c('xpos','xposInhom','xposHom'),
               labels=c('Experiment','Inhomogeneous','Homogeneous'))
table(d$pp)  

   Experiment Inhomogeneous   Homogeneous 
        57344         57344         57344 

The next figure shows all fixations of the three point processes (experimental data, inhomogeneous PP, homogeneous PP) during the first inspection of an image. As expected, fixation locations are not uniformly distributed in the experimental data and indicate inhomogeneity. The estimated intensity of all fixation locations is depicted by gray shading where darker areas represent higher intensities. The intensity of the experimental data was used for the simulation of the inhomogeneous PP.

dImg <- filter(d,image=='1' & nthPres=='First')
bw <- filter(sigma,img=='1' & pres=='First')$bw
ggplot(data=dImg,aes(x=x,y=y,col=pp)) +
  stat_density2d(aes(alpha=..density..),show.legend=FALSE,
                 geom="raster",contour=FALSE,h=bw*c(1,1),fill="black") +
  geom_point(size=.01) +
  facet_grid(.~pp) +
  labs(x='x-Coordinate [°]',y='y-Coordinate [°]',colour='Point Process') +
  coord_fixed(xlim=xrange,ylim=yrange,expand = FALSE) +
  theme_bw(base_size = 16) +
  theme(legend.position="none")