Loading and preparing data for analysis

data = read.table("XP3RayFiltering_logs.csv", header=TRUE, sep=",")

data = data %>% arrange(participantId, tech, block)

# filtering first trial of each set, because we don't know where in the scene, the cursor come from.
data = data %>% filter(trialId > 1)

# aggregating by set of trials, and computing error rate:
dataErrorMeans = data %>%
    group_by(participantId, tech, block) %>%
    summarize(errorRate = computeErrorRate(success))

# same aggregation as above, but we compute the mean time:
dataSuccessAggr = data %>%
    filter(success == "True") %>%
    group_by(participantId, tech, block) %>%
    summarize(meanFinalTimer = mean(finalTimer))

# aggregated data, with mean time and error rate in the same data table:
dataAggr = left_join(dataSuccessAggr, dataErrorMeans, by = c("participantId", "tech", "block"))

# useful if we exclude block 1 in some analysis:
dataAggrBlock23 = dataAggr %>% filter(block > 1)

techniques = unique(data$tech)
blocks = unique(data$block)

1 Selection time

1.1 Effect of blocks on selection time

1.1.1 Check the normality of data

data.long = melt(dataAggr, id = c("meanFinalTimer", "participantId", "tech", "block"))

data.long$tech = factor(data.long$tech)
data.long$block = factor(data.long$block)

m <- aov(meanFinalTimer ~ tech*block, data=data.long)
pander(normalCheck(m))

Shapiro-Wilk normality test

data: res W = 0.93816, p-value = 1.088e-05

Shapiro-Wilk normality test: res
Test statistic P value
0.9382 1.088e-05 * * *

1.1.2 Determine boxcox transform lambda to make residuals normal

boxcox(meanFinalTimer ~ tech*block, data=data.long, plotit=T)

A lambda of around -0.2 is effective.

1.1.3 Transform data

datatr = data.long %>%
    mutate(meanFinalTimer = meanFinalTimer^(-0.2))
m <- aov(meanFinalTimer ~ tech*block, data=datatr)
pander(normalCheck(m))

Shapiro-Wilk normality test

data: res W = 0.98447, p-value = 0.1291

Shapiro-Wilk normality test: res
Test statistic P value
0.9845 0.1291

1.1.4 Repeated measures ANOVA on transformed data

anova = ezANOVA(datatr, dv=.(meanFinalTimer), wid=.(participantId), within=.(block), detailed=TRUE)

kable(anova_apa(anova, sph_corr ="gg", es = "ges", print=FALSE))
effect text
(Intercept) F(1, 8) = 5276.69, p < .001, getasq > .99
block F(4, 32) = 2.18, p = .094, getasq = .02

1.1.5 Repeated measures ANOVA on non-transformed data

anova = ezANOVA(data.long, dv=.(meanFinalTimer), wid=.(participantId), within=.(block), detailed=TRUE)

kable(anova_apa(anova, sph_corr ="gg", es = "ges", print=FALSE))
effect text
(Intercept) F(1, 8) = 210.51, p < .001, getasq = .96
block F(2.12, 16.93) = 2.00, p = .164, getasq = .02

No learning effect.

1.2 Analysis with all blocks

1.2.1 Repeated measures ANOVA on transformed data

anova = ezANOVA(datatr, dv=.(meanFinalTimer), wid=.(participantId), within=.(tech,block), detailed=TRUE)

kable(anova_apa(anova, sph_corr ="gg", es = "ges", print=FALSE))
effect text
(Intercept) F(1, 8) = 5276.69, p < .001, getasq > .99
tech F(1.23, 9.82) = 2.05, p = .185, getasq = .02
block F(4, 32) = 2.18, p = .094, getasq = .01
tech:block F(3.00, 23.97) = 0.65, p = .593, getasq < .01

1.2.2 Repeated measures ANOVA Mean time on non-transformed data

dataSuccess.long = melt(dataAggr, id = c("meanFinalTimer", "participantId", "tech", "block"))

dataSuccess.long$tech = factor(dataSuccess.long$tech)
dataSuccess.long$block = factor(dataSuccess.long$block)

anova = ezANOVA(dataSuccess.long, dv=.(meanFinalTimer), wid=.(participantId), within=.(tech), detailed=TRUE)

kable(anova_apa(anova, sph_corr ="gg", es = "ges", print=FALSE))
effect text
(Intercept) F(1, 8) = 210.51, p < .001, getasq = .96
tech F(1.18, 9.47) = 1.16, p = .321, getasq = .02

1.2.3 Mean time per technique

tech meanFinalTimer
1_RayCasting 2.128227
2_RCst1EuroDirectRay 1.989203
3_RCst1EuroFilteredRay 2.130160

2 Error rate

2.0.1 Check the normality of data

data.long = melt(dataAggr, id = c("errorRate", "participantId", "tech", "block"))

data.long$tech = factor(data.long$tech)
data.long$block = factor(data.long$block)

m <- aov(errorRate ~ tech*block, data=data.long)
pander(normalCheck(m))

Shapiro-Wilk normality test

data: res W = 0.97502, p-value = 0.01381

Shapiro-Wilk normality test: res
Test statistic P value
0.975 0.01381 *

Error rate does not follow a normal distribution.

2.0.2 Determine boxcox transform lambda to make residuals normal

datatr0 = data.long %>% mutate(errorRate = errorRate + 10)
boxcox(errorRate ~ tech*block, data=datatr0, plotit=T)

Lambda is close to 0, corresponding to a log transformation.

2.0.3 Transform data

datatr = data.long %>%
    mutate(errorRate = log(errorRate + 10))
m <- aov(errorRate ~ tech*block, data=datatr)
pander(normalCheck(m))

Shapiro-Wilk normality test

data: res W = 0.98626, p-value = 0.1962

Shapiro-Wilk normality test: res
Test statistic P value
0.9863 0.1962

2.1 Effect of block on error rate

2.1.1 Repeated measures ANOVA on transformed data

anova = ezANOVA(datatr, dv=.(errorRate), wid=.(participantId), within=.(block), detailed=TRUE)

kable(anova_apa(anova, sph_corr ="gg", es = "ges", print=FALSE))
effect text
(Intercept) F(1, 8) = 1146.63, p < .001, getasq = .99
block F(4, 32) = 0.97, p = .436, getasq = .03

2.1.2 Repeated measures ANOVA on non-transformed data

anova = ezANOVA(data.long, dv=.(errorRate), wid=.(participantId), within=.(block), detailed=TRUE)

kable(anova_apa(anova, sph_corr ="gg", es = "ges", print=FALSE))
effect text
(Intercept) F(1, 8) = 54.92, p < .001, getasq = .83
block F(4, 32) = 1.37, p = .266, getasq = .05

No learning effect.

2.2 Analysis with all blocks

2.2.1 Overall error rate

kable(data.long %>% summarise(mean = mean(errorRate)))
mean
16.02339

2.2.2 Repeated measures ANOVA on transformed data

anova = ezANOVA(datatr, dv=.(errorRate), wid=.(participantId), within=.(block,tech), detailed=TRUE)

kable(anova_apa(anova, sph_corr ="gg", es = "ges", print=FALSE))
effect text
(Intercept) F(1, 8) = 1146.63, p < .001, getasq = .98
block F(4, 32) = 0.97, p = .436, getasq = .02
tech F(2, 16) = 12.19, p < .001, getasq = .21
block:tech F(8, 64) = 0.46, p = .880, getasq = .02

2.2.3 Repeated measures ANOVA Error rate on non-transformed data

data.long = melt(dataAggr, id = c("errorRate", "participantId", "tech", "block"))

data.long$tech = factor(data.long$tech)
data.long$block = factor(data.long$block)

anova = ezANOVA(data.long, dv=.(errorRate), wid=.(participantId), within=.(block,tech), detailed=TRUE)

kable(anova_apa(anova, sph_corr ="gg", es = "ges", print=FALSE))
effect text
(Intercept) F(1, 8) = 54.92, p < .001, getasq = .67
block F(4, 32) = 1.37, p = .266, getasq = .02
tech F(2, 16) = 11.98, p < .001, getasq = .25
block:tech F(3.01, 24.06) = 0.38, p = .768, getasq = .02

2.2.4 Error rate per technique

tech errorRate
1_RayCasting 25.26316
2_RCst1EuroDirectRay 11.11111
3_RCst1EuroFilteredRay 11.69591

2.2.4.1 Post-hoc analysis with Bonferroni correction

attach(datatr)
pw <- pairwise.t.test(errorRate, interaction(tech), p.adj = "bonferroni")
detach(datatr)
kable(pw$p.value)
1_RayCasting 2_RCst1EuroDirectRay
2_RCst1EuroDirectRay 5.5e-06 NA
3_RCst1EuroFilteredRay 2.9e-06 1

3 Preferences

techniques count
1_RayCasting 0
2_RCst1EuroDirectRay 2
3_RCst1EuroFilteredRay 7