---
title: "Orthogonality Study 5"
author: "Jim A.C. Everett & Simon Myers"
date: "`r format(Sys.time(), '%B %d, %Y')`"
output:
  html_document:
    theme: flatly
    code_folding: hide
    toc: true
    toc_depth: 3
    toc_float: 
      collapsed: TRUE
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
options(knitr.kable.NA = '')
```

***

# Description

***

In this study, we used a fully between subjects design in which participants read about an AI or human having either high or low instrumental rationality (i.e. intelligence), and then rated the same questions about intelligence, trust, and safety/danger as before. In addition, instead of a single question about "morality", we decomposed this into three questions about the agent’s perceived moral competence and three questions about the agent’s perceived moral motivation. This gave us a 2x2 fully between design, (Agent: Human vs AI) and (Intelligence: High vs Low).

***

# Setup

***

Before doing any analyses, we just need to load the data file and do some initial basis preparation.

```{r, results='hide', message=FALSE, warning=FALSE}
library(readr)
library(psych)
library(car)
library(tidyverse)
library(knitr)
library(kableExtra)
library(jmv)
library(BayesFactor)
library(effectsize)
library(gtsummary)
library(rempsyc)
library(see)
library(correlation)
library(lavaan)
library(emmeans)
library(ggnewscale)
library(patchwork)
library(lme4)
library(lmerTest)
library(broom)
library(broom.mixed)
```

We'll load the data and make sure the conditions are set as factors.

```{r}
# Load in data
df <- read.csv("Study_5_Data.csv", header=TRUE, stringsAsFactors=FALSE)

# set conditions as factors
df$Agent <- as.factor(df$Agent)
df$Level <- as.factor(df$Level)

# relevel factors

df$Level <- 
  factor(df$Level, 
         levels = c("Low Intelligence", "High Intelligence"))

df$Agent <- 
  factor(df$Agent, 
         levels = c("Human", "AI"))
```

***

We can just see the numbers per condition. In total, we have `r nrow(df)` participants.

```{r}
condition_table <- df %>%
  count(Agent, Level) %>%
  arrange(Agent, Level)


kable(condition_table,
      format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

Sometimes we'll need to just look at participants in the morality conditions, or the intelligence conditions, so we'll create dataframes for this. We'll actually do this for different "levels" as well as the full 8 condition breakdown, which might be interesting for the correlations.

```{r}
# First we break down just whether it is a human or an AI condition.
df_human <- df  %>% filter(Agent == "Human")
df_AI <- df  %>% filter(Agent == "AI")

# Second we break down just whether it is low or high intelligence condition.
df_low <- df %>% filter(Level == "Low Intelligence")
df_high <- df %>% filter(Level == "High Intelligence")

# Third we break down by both agent AND trait
df_low_intelligence_AI <- df %>% filter(Level == "Low Intelligence" & Agent == "AI")
df_high_intelligence_AI <- df %>% filter(Level == "High Intelligence" & Agent == "AI")
df_low_intelligence_human <- df %>% filter(Level == "Low Intelligence" & Agent == "AI")
df_high_intelligence_human <- df %>% filter(Level == "High Intelligence" & Agent == "AI")
```

***

We can get participant age for the reporting.

```{r}
# Summarize age
age_table <- df %>%
  summarise(
    mean_age = mean(Age, na.rm = TRUE),
    sd_age = sd(Age, na.rm = TRUE),
    min_age = min(Age, na.rm = TRUE),
    max_age = max(Age, na.rm = TRUE)
  )

kable(age_table, format = "html",
            row.names = FALSE, digits = 2) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

And report gender.

```{r}
df$Gender <- as.factor(df$Gender)

kable(table(df$Gender), format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

As outlined in the pre-reg, three of the items were about moral competence and three were about moral motivation, so we'll just check the Cronbach's alpha reliability for combining them together as intended.

```{r}
# Moral Competence
alpha_competence <- psych::alpha(df %>% select(Moral_Knowledge, Moral_Predict, Moral_Explain))

# Moral Competence (Comparison)
alpha_competence_comp <- psych::alpha(df %>% select(Moral_Knowledge_Comparison, Moral_Predict_Comparison, Moral_Explain_Comparison))

# Moral Motivation
alpha_motivation <- psych::alpha(df %>% select(Moral_Help, Moral_Harm, Moral_Fair))

# Moral Motivation (Comparison)
alpha_motivation_comp <- psych::alpha(df %>% select(Moral_Help_Comparison, Moral_Harm_Comparison, Moral_Fair_Comparison))

alpha_table <- tibble(
  Scale = c(
    "Moral_Competence",
    "Moral_Competence_Comparison",
    "Moral_Motivation",
    "Moral_Motivation_Comparison"
  ),
  Cronbach_Alpha = c(
    alpha_competence$total$raw_alpha,
    alpha_competence_comp$total$raw_alpha,
    alpha_motivation$total$raw_alpha,
    alpha_motivation_comp$total$raw_alpha
  )
)

kable(alpha_table, format = "html", digits = 3, row.names = FALSE) %>%
  kable_styling(bootstrap_options = "striped", full_width = FALSE, position = "left")
```

This confirms we are justified in creating averages.

***

# Manipulation Check

We start looking at our manipulation check,  looking at ratings of or intelligence by the level condition (high vs low intelligence), but also look at whether this depends on the type of Agent. 

***

```{r, message=FALSE}
# Compute model
contrasts(df$Level) <- contr.sum
contrasts(df$Agent) <- contr.sum
raw.model <- lm(Intelligent ~ Level * Agent, data = df)

# Extract ANOVA into table
model <- car::Anova(raw.model, type = 3)

# Get effect size
eta <- eta_squared(model, partial = TRUE)

# Get tidy ANOVA
anova_df <- as.data.frame(model)

# Rename rows from ANOVA table
anova_df <- anova_df %>%
  rownames_to_column("Term") %>%
  rename(
    SS = `Sum Sq`,
    df = Df,
    F = `F value`,
    p = `Pr(>F)`
  )

# Combine with partial eta square
combined_table <- left_join(anova_df, eta, by = c("Term" = "Parameter"))

# Select ones we want for APA and rename
final_table <- combined_table %>% 
  select(Term, df, F, p, Eta2_partial) %>% 
  rename(
    `ηp²` = Eta2_partial
  )

# Format test results

final_table <- final_table %>%
  mutate(
    F = round(F, 2),
    `ηp²` = round(`ηp²`, 2),
    p = case_when(
      is.na(p) ~ NA_character_,
      as.numeric(p) < 0.001 ~ "<.001",
      TRUE ~ sprintf("%.3f", as.numeric(p))
    )
  )

kable(final_table, 
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived Intelligence by Intelligence Level and Agent Type</span>",
      row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

# Simple Effects by Condition

***

### Descriptives & Simple Effects

Now we will turn to look at different effects by condition. First, we will look at descriptives and simple effects of high vs low level, and we'll do this seperately for the different conditions by agent (human vs AI).

***

#### AI Conditions

```{r}
summary_table_AI <- df %>%
  filter(Agent == "AI") %>%
  select(Level, Intelligent, Intelligent_Comparison, 
         Moral_Competence, Moral_Competence_Comparison,
         Moral_Motivation, Moral_Motivation_Comparison,
         Trust, Danger) %>%
  pivot_longer(-Level, names_to = "Variable", values_to = "Value") %>%
  mutate(Variable = factor(Variable, 
                           levels = c("Intelligent", "Intelligent_Comparison", 
                                      "Moral_Competence", "Moral_Competence_Comparison",
                                      "Moral_Motivation", "Moral_Motivation_Comparison",
                                      "Trust", "Danger"))) %>%
  group_by(Variable, Level) %>%
summarise(
  min = round(min(Value, na.rm = TRUE), 2),
  max = round(max(Value, na.rm = TRUE), 2),
  mean = round(mean(Value, na.rm = TRUE), 2),
  sd = round(sd(Value, na.rm = TRUE), 2),
  .groups = "drop"
)

summary_table_AI <- summary_table_AI %>%
  mutate(Variable = fct_recode(
  Variable,
  "Intelligence" = "Intelligent",
  "Intelligence (Compared to Average Person)" = "Intelligent_Comparison",
  "Moral Competence" = "Moral_Competence",
  "Moral Competence (Compared to Average Person)" = "Moral_Competence_Comparison",
  "Moral Motivation (Compared to Average Person)" = "Moral_Motivation_Comparison"))


kable(summary_table_AI,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Ratings by Intelligence Level (AI Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

First, for consistency with Studies 1a and 1b and 3, we'll do the Welch's t-test.

```{r}
# T-test
results <- t.test(Intelligent ~ Level, data = df_AI, var.equal = FALSE)

# Rounding
t_val <- round(results$statistic, 2)
df_val <- sprintf("%.2f", results$parameter)  # force 2 decimal places
p_val <- if (results$p.value < 0.001) "<0.001" else sprintf("%.3f", results$p.value)

# Effect size
effect_size <- cohens_d(Intelligent ~ Level, data = df_AI)
d_val <- round(effect_size$Cohens_d, 2)

# Bayes Factor
bf_result <- ttestBF(formula = Intelligent ~ Level, data = df_AI)
bf_numeric <- as.numeric(exp(bf_result@bayesFactor$bf))
bf_exponent <- floor(log10(bf_numeric))
bf_mantissa <- bf_numeric / (10^bf_exponent)
bf_apa <- paste0(sprintf("%.2f", bf_mantissa), " × 10^", bf_exponent)

# Combine into a table
final_table <- data.frame(
  `_t_` = t_val,
  `df` = df_val,
  `_p_` = p_val,
  `Bayes Factor` = format(bf_numeric, scientific = TRUE, digits = 6),
  `Bayes Factor APA` = bf_apa,
  `Cohen's _d_` = d_val,
  check.names = FALSE
)

kable(final_table, format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

To save time for other analyses we create a function to do produce the output for the variables which we then pull into a table.

```{r}
welch.t.test.bf <- function(DV, IV, data, labeliv = "IV", labeldv = "DV") {
  # Build formula from strings
  formula <- as.formula(paste(DV, "~", IV))

  # Welch's t-test
  results <- t.test(formula, data = data, var.equal = FALSE)
  
  # Format test results
  results_table <- data.frame(
    t = round(results$statistic, 2),
    df = sprintf("%.2f", results$parameter),
    p <- if (results$p.value < 0.001) "<0.001" else sprintf("%.3f", results$p.value)
  )

  # Effect size
  effect_size <- cohens_d(formula, data = data)
  cohen_d <- round(effect_size$Cohens_d, 2)

  # Bayes Factor
  bf_result <- ttestBF(formula = formula, data = data)
  bf_numeric <- exp(bf_result@bayesFactor$bf)
  bf_numeric <- as.numeric(exp(bf_result@bayesFactor$bf))
  bf_exponent <- floor(log10(bf_numeric))
  bf_mantissa <- bf_numeric / (10^bf_exponent)
  bf_apa <- paste0(sprintf("%.2f", bf_mantissa), " × 10^", bf_exponent)

  # Combine into final table
  final_table <- data.frame(
    "_t_" = results_table$t,
    "df" = results_table$df,
    "_p_" = results_table$p,
    "Bayes Factor" = bf_numeric,
    "Bayes Factor APA" = bf_apa,
    "Cohen's _d_" = cohen_d,
    check.names = FALSE
  )

  return(final_table)
}
```

After creating the function we can check it shows the same results.

```{r}
intelligence <- welch.t.test.bf(data = df_AI, DV = "Intelligent", IV = "Level", labeliv = "Level", labeldv = "Intelligence")
kable(intelligence, format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

Now we know it works, we can easily do the same for future analyses and create tables showing variables together.

```{r}
intelligence <- welch.t.test.bf(data = df_AI, 
                                DV = "Intelligent", IV = "Level", 
                                labeliv = "Level", labeldv = "Intelligence")

intelligence_comparison <- welch.t.test.bf(data = df_AI, 
                                           DV = "Intelligent_Comparison", IV = "Level", 
                                           labeliv = "Level", labeldv = "Intelligence (Compared to Average Person)")

moral_competence <- welch.t.test.bf(data = df_AI, 
                                DV = "Moral_Competence", IV = "Level", 
                                labeliv = "Level", labeldv = "Moral Competence")

moral_competence_comparison <- welch.t.test.bf(data = df_AI, 
                                           DV = "Moral_Competence_Comparison", IV = "Level", 
                                           labeliv = "Level", labeldv = "Moral Competence (Compared to Average Person)")

moral_motivation <- welch.t.test.bf(data = df_AI, 
                                DV = "Moral_Motivation", IV = "Level", 
                                labeliv = "Level", labeldv = "Moral Motivation")

moral_motivation_comparison <- welch.t.test.bf(data = df_AI, 
                                           DV = "Moral_Motivation_Comparison", IV = "Level", 
                                           labeliv = "Level", labeldv = "Moral Motivation (Compared to Average Person)")

trust <- welch.t.test.bf(data = df_AI, 
                         DV = "Trust", IV = "Level", 
                         labeliv = "Level", labeldv = "Trust")

danger <- welch.t.test.bf(data = df_AI, 
                          DV = "Danger", IV = "Level", 
                          labeliv = "Level", labeldv = "Danger")

# Add a DV label column to each
intelligence$DV <- "Intelligence"
intelligence_comparison$DV <- "Intelligence (Compared to Average Person)"
moral_competence$DV <- "Moral Competence"
moral_competence_comparison$DV <- "Moral Competence (Compared to Average Person)"
moral_motivation$DV <- "Moral Motivation"
moral_motivation_comparison$DV <- "Moral Motivation (Compared to Average Person)"
trust$DV <- "Trust"
danger$DV <- "Danger"

# Combine into a single data frame
combined_results <- rbind(intelligence,intelligence_comparison,
                          moral_competence, moral_competence_comparison,
                          moral_motivation, moral_motivation_comparison,
                          trust,danger)

# Move DV column to the front
combined_results <- combined_results[, c("DV", setdiff(names(combined_results), "DV"))]

kable(combined_results,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Ratings by Intelligence Level (AI Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```

***

#### Human Conditions

```{r}
summary_table_human <- df %>%
  filter(Agent == "Human") %>%
  select(Level, Intelligent, Intelligent_Comparison, 
         Moral_Competence, Moral_Competence_Comparison,
         Moral_Motivation, Moral_Motivation_Comparison,
         Trust, Danger) %>%
  pivot_longer(-Level, names_to = "Variable", values_to = "Value") %>%
  mutate(Variable = factor(Variable, 
                           levels = c("Intelligent", "Intelligent_Comparison", 
                                      "Moral_Competence", "Moral_Competence_Comparison",
                                      "Moral_Motivation", "Moral_Motivation_Comparison",
                                      "Trust", "Danger"))) %>%
  group_by(Variable, Level) %>%
summarise(
  min = round(min(Value, na.rm = TRUE), 2),
  max = round(max(Value, na.rm = TRUE), 2),
  mean = round(mean(Value, na.rm = TRUE), 2),
  sd = round(sd(Value, na.rm = TRUE), 2),
  .groups = "drop"
)

summary_table_human <- summary_table_human %>%
  mutate(Variable = fct_recode(
  Variable,
  "Intelligence" = "Intelligent",
  "Intelligence (Compared to Average Person)" = "Intelligent_Comparison",
  "Moral Competence" = "Moral_Competence",
  "Moral Competence (Compared to Average Person)" = "Moral_Competence_Comparison",
  "Moral Motivation (Compared to Average Person)" = "Moral_Motivation_Comparison"))


kable(summary_table_human, 
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Ratings by Intelligence Level (Human Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***
```{r}
intelligence <- welch.t.test.bf(data = df_human, 
                                DV = "Intelligent", IV = "Level", 
                                labeliv = "Level", labeldv = "Intelligence")

intelligence_comparison <- welch.t.test.bf(data = df_human, 
                                           DV = "Intelligent_Comparison", IV = "Level", 
                                           labeliv = "Level", labeldv = "Intelligence (Compared to Average Person)")

moral_competence <- welch.t.test.bf(data = df_human, 
                                DV = "Moral_Competence", IV = "Level", 
                                labeliv = "Level", labeldv = "Moral Competence")

moral_competence_comparison <- welch.t.test.bf(data = df_human, 
                                           DV = "Moral_Competence_Comparison", IV = "Level", 
                                           labeliv = "Level", labeldv = "Moral Competence (Compared to Average Person)")

moral_motivation <- welch.t.test.bf(data = df_human, 
                                DV = "Moral_Motivation", IV = "Level", 
                                labeliv = "Level", labeldv = "Moral Motivation")

moral_motivation_comparison <- welch.t.test.bf(data = df_human, 
                                           DV = "Moral_Motivation_Comparison", IV = "Level", 
                                           labeliv = "Level", labeldv = "Moral Motivation (Compared to Average Person)")

trust <- welch.t.test.bf(data = df_human, 
                         DV = "Trust", IV = "Level", 
                         labeliv = "Level", labeldv = "Trust")

danger <- welch.t.test.bf(data = df_human, 
                          DV = "Danger", IV = "Level", 
                          labeliv = "Level", labeldv = "Danger")

# Add a DV label column to each
intelligence$DV <- "Intelligence"
intelligence_comparison$DV <- "Intelligence (Compared to Average Person)"
moral_competence$DV <- "Moral Competence"
moral_competence_comparison$DV <- "Moral Competence (Compared to Average Person)"
moral_motivation$DV <- "Moral Motivation"
moral_motivation_comparison$DV <- "Moral Motivation (Compared to Average Person)"
trust$DV <- "Trust"
danger$DV <- "Danger"

# Combine into a single data frame
combined_results <- rbind(intelligence,intelligence_comparison,
                          moral_competence, moral_competence_comparison,
                          moral_motivation, moral_motivation_comparison,
                          trust,danger)

# Move DV column to the front
combined_results <- combined_results[, c("DV", setdiff(names(combined_results), "DV"))]

kable(combined_results, 
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Ratings by Intelligence Level (Human Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```

***

# ANOVAs

***

## Moral Competence

***

### General Rating

First, we ask whether high or low intelligence predicts rated moral competence for humans and AI on the general question. 

***

```{r, message=FALSE, warning=FALSE}
# Compute model
contrasts(df$Level) <- contr.sum
contrasts(df$Agent) <- contr.sum
model <- lm(Moral_Competence ~ Level * Agent, data = df)

# Extract ANOVA into table
model <- car::Anova(model, type = 3)

# Get effect size
eta <- eta_squared(model, partial = TRUE)

# Get tidy ANOVA
anova_df <- as.data.frame(model)

# Remove intercept row
anova_df <- anova_df[-1, ]

# Rename rows from ANOVA table
anova_df <- anova_df %>%
  rownames_to_column("Term") %>%
  rename(
    SS = `Sum Sq`,
    df = Df,
    F = `F value`,
    p = `Pr(>F)`
  )

# Combine with partial eta square
combined_table <- left_join(anova_df, eta, by = c("Term" = "Parameter"))

# Select ones we want for APA and rename
final_table <- combined_table %>% 
  select(Term, df, F, p, Eta2_partial) %>% 
  rename(
    `ηp²` = Eta2_partial
  )

# Format test results

final_table <- final_table %>%
  mutate(
    F = round(F, 2),
    `ηp²` = round(`ηp²`, 2),
    p = case_when(
      is.na(p) ~ NA_character_,
      as.numeric(p) < 0.001 ~ "<.001",
      TRUE ~ sprintf("%.3f", as.numeric(p))
    )
  )

# Rename the rows 
final_table <- final_table %>%
  mutate(
    Term = case_when(
      Term == "Level" ~ "Level",
      Term == "Agent" ~ "Agent",
      Term == "Level:Agent" ~ "Level × Agent",
      TRUE ~ Term
    )
  )


kable(final_table, 
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived Moral Competence by Intelligence Level and Agent Type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
moral_competence_table <- df %>%
  group_by(Agent, Level) %>%
  summarise(
    "Mean Moral Competence" = mean(Moral_Competence),
    "SD" = sd(Moral_Competence),
    n = n(),
    .groups = "drop"
  )

kable(moral_competence_table,
      format = "html", digits = 2,
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived Moral Competence by Intelligence Level and Agent Type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

We now break down this interaction effect. We can again, just so it's all in the same place, look at differences between high and low intelligence on ratings of moral competence for humans and AI seperately.

```{r}
moral_competence_AI <- welch.t.test.bf(data = df_AI, 
                                DV = "Moral_Competence", IV = "Level", 
                                labeliv = "Level", labeldv = "Moral Competence")

kable(moral_competence_AI, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Moral Competence by Intelligence Level (AI Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
moral_competence_human <- welch.t.test.bf(data = df_human, 
                                DV = "Moral_Competence", IV = "Level", 
                                labeliv = "Level", labeldv = "Moral Competence")

kable(moral_competence_human, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Moral Competence by Intelligence Level (Human Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

Above we looked at the difference between high and low intelligence for humans and AI separately, here we are looking at the difference between human and AI for high and low separately.

```{r}
simple_effect_low <- welch.t.test.bf(data = df_low, DV = "Moral_Competence", IV = "Agent", labeliv = "Agent", labeldv = "Moral Competence")

kable(simple_effect_low,
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Moral Competence by Agent Type (Low Intelligence Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
simple_effect_high <- welch.t.test.bf(data = df_high, DV = "Moral_Competence", IV = "Agent", labeliv = "Agent", labeldv = "Moral Competence")

kable(simple_effect_high, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Moral Competence by Agent Type (High Intelligence Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

We'll then make the figure that we will combine and show in a minute.

```{r, fig.height=4, fig.width=4}
# Fit the model
model <- lm(Moral_Competence ~ Level * Agent, data = df) # model
emm <- emmeans(model, ~ Level * Agent) # Estimated marginal means
emm_df <- as.data.frame(emm) # Convert to data frame for plotting

# Define consistent colors
fill_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")
line_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")

# Ensure correct factor order
df$Level <- factor(df$Level, levels = c("Low Intelligence", "High Intelligence"))
emm_df$Level <- factor(emm_df$Level, levels = c("Low Intelligence", "High Intelligence"))

# Create the plot
moralcompetence_plot <- ggplot() +

  # Jittered individual data points (filled circles, no outline)
geom_jitter(
  data = df,
  aes(x = Level, y = Moral_Competence, fill = Agent),
  shape = 21,
  size = 2,
  stroke = 0.1,           # tiny border just to make visible
  color = "gray80",       # light neutral outline
  alpha = 0.15,
  position = position_jitterdodge(dodge.width = 0.7, jitter.width = 0.35, jitter.height = 0.35)
)+
  
  # Estimated marginal means with visible outline
geom_pointrange(
  data = emm_df,
  aes(
    x = Level,
    y = emmean,
    ymin = lower.CL,
    ymax = upper.CL,
    group = Agent,
    fill = Agent,
    colour = Agent
  ),
  position = position_dodge(width = 0.7),
  shape = 21,         # Fillable circle
  size = 1.2,         # Thicker CI line
  stroke = 1.2,       # Thicker point border
  fatten = 3,         # Large mean point
  show.legend = TRUE
)+
  

  # Color scales
  scale_color_manual(values = line_colors) +
  scale_fill_manual(values = fill_colors) +

  # Axis labels and limits
  labs(
    title = "Perceived Moral Competence \n from Intelligence Level",
    x = "Intelligence Level",
    y = "Moral Competence",
    fill = NULL,
    colour = NULL
  ) +
  coord_cartesian(ylim = c(1, 7)) +
  scale_y_continuous(breaks = 1:7) +

  # Theme and legend styling
  theme_classic() +
  theme(
    text = element_text(size = 12),
    axis.title = element_text(size = 13),
    axis.text = element_text(size = 12),
    axis.title.y = element_text(margin = margin(r = 10)),
    axis.title.x = element_blank(),
    plot.title = element_text(size = 12, hjust = 0.5, margin = margin(b=10)),  # Centered title
    legend.position = "bottom",
    legend.direction = "horizontal",
    legend.justification = "center",
    legend.box.margin = margin(t = -5),
    legend.key.height = unit(1.2, "lines"),
    legend.key.width = unit(1.2, "lines"),
    legend.text = element_text(size = 12)
  )


moralcompetence_plot
```

***

### Comparison Question

```{r, message=FALSE, warning=FALSE}
# Compute model
contrasts(df$Level) <- contr.sum
contrasts(df$Agent) <- contr.sum
model <- lm(Moral_Competence_Comparison ~ Level * Agent, data = df)

# Extract ANOVA into table
model <- car::Anova(model, type = 3)

# Get effect size
eta <- eta_squared(model, partial = TRUE)

# Get tidy ANOVA
anova_df <- as.data.frame(model)

# Remove intercept row
anova_df <- anova_df[-1, ]

# Rename rows from ANOVA table
anova_df <- anova_df %>%
  rownames_to_column("Term") %>%
  rename(
    SS = `Sum Sq`,
    df = Df,
    F = `F value`,
    p = `Pr(>F)`
  )

# Combine with partial eta square
combined_table <- left_join(anova_df, eta, by = c("Term" = "Parameter"))

# Select ones we want for APA and rename
final_table <- combined_table %>% 
  select(Term, df, F, p, Eta2_partial) %>% 
  rename(
    `ηp²` = Eta2_partial
  )

# Format test results

final_table <- final_table %>%
  mutate(
    F = round(F, 2),
    `ηp²` = round(`ηp²`, 2),
    p = case_when(
      is.na(p) ~ NA_character_,
      as.numeric(p) < 0.001 ~ "<.001",
      TRUE ~ sprintf("%.3f", as.numeric(p))
    )
  )

# Rename the rows 
final_table <- final_table %>%
  mutate(
    Term = case_when(
      Term == "Level" ~ "Level",
      Term == "Agent" ~ "Agent",
      Term == "Level:Agent" ~ "Level × Agent",
      TRUE ~ Term
    )
  )


kable(final_table, 
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived Moral Competence (Comparison) by Intelligence Level and Agent Type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
moral_competence_comparison_table <- df %>%
  group_by(Agent, Level) %>%
  summarise(
    "Mean Moral Competence" = mean(Moral_Competence_Comparison),
    "SD" = sd(Moral_Competence_Comparison),
    n = n(),
    .groups = "drop"
  )

kable(moral_competence_comparison_table,
      format = "html", digits = 2,
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived Moral Competence (Comparison) by Intelligence Level and Agent Type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

We now break down this interaction effect. We can again, just so it's all in the same place, look at differences between high and low intelligence on ratings of moral competence for humans and AI seperately.

```{r}
moral_competence_AI <- welch.t.test.bf(data = df_AI, 
                                DV = "Moral_Competence_Comparison", IV = "Level", 
                                labeliv = "Level", labeldv = "Moral Competence (Comparison)")

kable(moral_competence_AI, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Moral Competence (Comparison) by Intelligence Level (AI Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
moral_competence_human <- welch.t.test.bf(data = df_human, 
                                DV = "Moral_Competence_Comparison", IV = "Level", 
                                labeliv = "Level", labeldv = "Moral Competence (Comparison)")

kable(moral_competence_human, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Moral Competence (Comparison) by Intelligence Level (Human Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

Above we looked at the difference between high and low intelligence for humans and AI separately, here we are looking at the difference between human and AI for high and low separately.

```{r}
simple_effect_low <- welch.t.test.bf(data = df_low, 
                                     DV = "Moral_Competence_Comparison", IV = "Agent", 
                                     labeliv = "Agent", labeldv = "Moral Competence (Comparison)")

kable(simple_effect_low, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Moral Competence (Comparison) by Agent Type (Low Intelligence Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
simple_effect_high <- welch.t.test.bf(data = df_high, DV = "Moral_Competence_Comparison", IV = "Agent", 
                                      labeliv = "Agent", labeldv = "Moral Competence (Comparison)")

kable(simple_effect_high, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Moral Competence (Comparison) by Agent Type (High Intelligence Only)</span>",
      row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

We'll then make the figure that we will combine and show in a minute.

```{r, fig.height=4, fig.width=4}
# Fit the model
model <- lm(Moral_Competence_Comparison ~ Level * Agent, data = df) # model
emm <- emmeans(model, ~ Level * Agent) # Estimated marginal means
emm_df <- as.data.frame(emm) # Convert to data frame for plotting

# Define consistent colors
fill_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")
line_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")

# Ensure correct factor order
df$Level <- factor(df$Level, levels = c("Low Intelligence", "High Intelligence"))
emm_df$Level <- factor(emm_df$Level, levels = c("Low Intelligence", "High Intelligence"))

# Create the plot
moral_competence_comparison_plot <- ggplot() +

  # Jittered individual data points (filled circles, no outline)
geom_jitter(
  data = df,
  aes(x = Level, y = Moral_Competence_Comparison, fill = Agent),
  shape = 21,
  size = 2,
  stroke = 0.1,           # tiny border just to make visible
  color = "gray80",       # light neutral outline
  alpha = 0.15,
  position = position_jitterdodge(dodge.width = 0.7, jitter.width = 0.35, jitter.height = 0.35)
)+
  
  # Reference line for comparison baseline
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray60", linewidth = 0.7) +
  
  # Estimated marginal means with visible outline
geom_pointrange(
  data = emm_df,
  aes(
    x = Level,
    y = emmean,
    ymin = lower.CL,
    ymax = upper.CL,
    group = Agent,
    fill = Agent,
    colour = Agent
  ),
  position = position_dodge(width = 0.7),
  shape = 21,         # Fillable circle
  size = 1.2,         # Thicker CI line
  stroke = 1.2,       # Thicker point border
  fatten = 3,         # Large mean point
  show.legend = TRUE
)+
  

  # Color scales
  scale_color_manual(values = line_colors) +
  scale_fill_manual(values = fill_colors) +

  # Axis labels and limits
  labs(
    title = "Perceived Moral Competence \n from Intelligence Level",
    x = "Intelligence Level",
     y = expression(atop("Moral Competence", "(Comparison to Average Person)")),
    fill = NULL,
    colour = NULL
  ) +
  coord_cartesian(ylim = c(-3, 3)) +
  scale_y_continuous(breaks = -3:3) +

  # Theme and legend styling
  theme_classic() +
  theme(
    text = element_text(size = 12),
    axis.title = element_text(size = 13),
    axis.text = element_text(size = 12),
    axis.title.y = element_text(margin = margin(r = 10)),
    axis.title.x = element_blank(),
    plot.title = element_text(size = 12, hjust = 0.5, margin = margin(b=10)),  # Centered title
    legend.position = "bottom",
    legend.direction = "horizontal",
    legend.justification = "center",
    legend.box.margin = margin(t = -5),
    legend.key.height = unit(1.2, "lines"),
    legend.key.width = unit(1.2, "lines"),
    legend.text = element_text(size = 12)
  )

moral_competence_comparison_plot
```

***


## Moral Motivation

***

### General Ratings

First, we ask whether high or low intelligence predicts rated moral motivation for humans and AI.

***

```{r, message=FALSE, warning=FALSE}
# Compute model
contrasts(df$Level) <- contr.sum
contrasts(df$Agent) <- contr.sum
model <- lm(Moral_Motivation ~ Level * Agent, data = df)

# Extract ANOVA into table
model <- car::Anova(model, type = 3)

# Get effect size
eta <- eta_squared(model, partial = TRUE)

# Get tidy ANOVA
anova_df <- as.data.frame(model)

# Remove intercept row
anova_df <- anova_df[-1, ]

# Rename rows from ANOVA table
anova_df <- anova_df %>%
  rownames_to_column("Term") %>%
  rename(
    SS = `Sum Sq`,
    df = Df,
    F = `F value`,
    p = `Pr(>F)`
  )

# Combine with partial eta square
combined_table <- left_join(anova_df, eta, by = c("Term" = "Parameter"))

# Select ones we want for APA and rename
final_table <- combined_table %>% 
  select(Term, df, F, p, Eta2_partial) %>% 
  rename(
    `ηp²` = Eta2_partial
  )

# Format test results

final_table <- final_table %>%
  mutate(
    F = round(F, 2),
    `ηp²` = round(`ηp²`, 2),
    p = case_when(
      is.na(p) ~ NA_character_,
      as.numeric(p) < 0.001 ~ "<.001",
      TRUE ~ sprintf("%.3f", as.numeric(p))
    )
  )

# Rename the rows 
final_table <- final_table %>%
  mutate(
    Term = case_when(
      Term == "Level" ~ "Level",
      Term == "Agent" ~ "Agent",
      Term == "Level:Agent" ~ "Level × Agent",
      TRUE ~ Term
    )
  )


kable(final_table, 
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived Moral Motivation by Intelligence Level and Agent Type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
moral_motivation_table <- df %>%
  group_by(Agent, Level) %>%
  summarise(
    "Mean Moral Motivation" = mean(Moral_Motivation),
    "SD" = sd(Moral_Motivation),
    n = n(),
    .groups = "drop"
  )

kable(moral_motivation_table,
      format = "html", digits = 2,
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived Moral Motivation by Intelligence Level and Agent Type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

We now break down this interaction effect. We can again, just so it's all in the same place, look at differences between high and low intelligence on ratings of moral competence for humans and AI seperately.

```{r}
moral_motivation_AI <- welch.t.test.bf(data = df_AI, 
                                DV = "Moral_Motivation", IV = "Level", 
                                labeliv = "Level", labeldv = "Moral Motivation")

kable(moral_motivation_AI, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Moral Motivation by Intelligence Level (AI Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
moral_motivation_human <- welch.t.test.bf(data = df_human, 
                                DV = "Moral_Motivation", IV = "Level", 
                                labeliv = "Level", labeldv = "Moral Motivation")

kable(moral_motivation_human, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Moral Motivation by Intelligence Level (Human Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

Above we looked at the difference between high and low intelligence for humans and AI separately, here we are looking at the difference between human and AI for high and low separately.

```{r}
simple_effect_low <- welch.t.test.bf(data = df_low, DV = "Moral_Motivation", IV = "Agent", labeliv = "Agent", labeldv = "Moral Motivation")

kable(simple_effect_low, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Moral Motivation by Agent Type (Low Intelligence Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
simple_effect_high <- welch.t.test.bf(data = df_high, DV = "Moral_Motivation", IV = "Agent", labeliv = "Agent", labeldv = "Moral Motivation")

kable(simple_effect_high, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Moral Motivation by Agent Type (High Intelligence Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

We'll then make the figure that we will combine and show in a minute.

```{r, fig.height=4, fig.width=4}
# Fit the model
model <- lm(Moral_Motivation ~ Level * Agent, data = df) # model
emm <- emmeans(model, ~ Level * Agent) # Estimated marginal means
emm_df <- as.data.frame(emm) # Convert to data frame for plotting

# Define consistent colors
fill_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")
line_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")

# Ensure correct factor order
df$Level <- factor(df$Level, levels = c("Low Intelligence", "High Intelligence"))
emm_df$Level <- factor(emm_df$Level, levels = c("Low Intelligence", "High Intelligence"))

# Create the plot
moralmotivation_plot <- ggplot() +

  # Jittered individual data points (filled circles, no outline)
geom_jitter(
  data = df,
  aes(x = Level, y = Moral_Motivation, fill = Agent),
  shape = 21,
  size = 2,
  stroke = 0.1,           # tiny border just to make visible
  color = "gray80",       # light neutral outline
  alpha = 0.15,
  position = position_jitterdodge(dodge.width = 0.7, jitter.width = 0.35, jitter.height = 0.35)
)+
  
  # Estimated marginal means with visible outline
geom_pointrange(
  data = emm_df,
  aes(
    x = Level,
    y = emmean,
    ymin = lower.CL,
    ymax = upper.CL,
    group = Agent,
    fill = Agent,
    colour = Agent
  ),
  position = position_dodge(width = 0.7),
  shape = 21,         # Fillable circle
  size = 1.2,         # Thicker CI line
  stroke = 1.2,       # Thicker point border
  fatten = 3,         # Large mean point
  show.legend = TRUE
)+
  

  # Color scales
  scale_color_manual(values = line_colors) +
  scale_fill_manual(values = fill_colors) +

  # Axis labels and limits
  labs(
    title = "Perceived Moral Motivation \n from Intelligence Level",
    x = "Intelligence Level",
    y = "Moral Motivation",
    fill = NULL,
    colour = NULL
  ) +
  coord_cartesian(ylim = c(1, 7)) +
  scale_y_continuous(breaks = 1:7) +

  # Theme and legend styling
  theme_classic() +
  theme(
    text = element_text(size = 12),
    axis.title = element_text(size = 13),
    axis.text = element_text(size = 12),
    axis.title.y = element_text(margin = margin(r = 10)),
    axis.title.x = element_blank(),
    plot.title = element_text(size = 12, hjust = 0.5, margin = margin(b=10)),  # Centered title
    legend.position = "bottom",
    legend.direction = "horizontal",
    legend.justification = "center",
    legend.box.margin = margin(t = -5),
    legend.key.height = unit(1.2, "lines"),
    legend.key.width = unit(1.2, "lines"),
    legend.text = element_text(size = 12)
  )


moralmotivation_plot
```

***

### Comparison Question

```{r, message=FALSE, warning=FALSE}
# Compute model
contrasts(df$Level) <- contr.sum
contrasts(df$Agent) <- contr.sum
model <- lm(Moral_Motivation_Comparison ~ Level * Agent, data = df)

# Extract ANOVA into table
model <- car::Anova(model, type = 3)

# Get effect size
eta <- eta_squared(model, partial = TRUE)

# Get tidy ANOVA
anova_df <- as.data.frame(model)

# Remove intercept row
anova_df <- anova_df[-1, ]

# Rename rows from ANOVA table
anova_df <- anova_df %>%
  rownames_to_column("Term") %>%
  rename(
    SS = `Sum Sq`,
    df = Df,
    F = `F value`,
    p = `Pr(>F)`
  )

# Combine with partial eta square
combined_table <- left_join(anova_df, eta, by = c("Term" = "Parameter"))

# Select ones we want for APA and rename
final_table <- combined_table %>% 
  select(Term, df, F, p, Eta2_partial) %>% 
  rename(
    `ηp²` = Eta2_partial
  )

# Format test results

final_table <- final_table %>%
  mutate(
    F = round(F, 2),
    `ηp²` = round(`ηp²`, 2),
    p = case_when(
      is.na(p) ~ NA_character_,
      as.numeric(p) < 0.001 ~ "<.001",
      TRUE ~ sprintf("%.3f", as.numeric(p))
    )
  )

# Rename the rows 
final_table <- final_table %>%
  mutate(
    Term = case_when(
      Term == "Level" ~ "Level",
      Term == "Agent" ~ "Agent",
      Term == "Level:Agent" ~ "Level × Agent",
      TRUE ~ Term
    )
  )


kable(final_table, 
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived Moral Motivation (Comparison) by Intelligence Level and Agent Type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
moral_motivation_comparison_table <- df %>%
  group_by(Agent, Level) %>%
  summarise(
    "Mean Moral Motivation" = mean(Moral_Motivation_Comparison),
    "SD" = sd(Moral_Motivation_Comparison),
    n = n(),
    .groups = "drop"
  )

kable(moral_motivation_comparison_table,
      format = "html", digits = 2,
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived Moral Motivation (Comparison) by Intelligence Level and Agent Type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

We now break down this interaction effect. We can again, just so it's all in the same place, look at differences between high and low intelligence on ratings of moral competence for humans and AI seperately.

```{r}
moral_motivation_AI <- welch.t.test.bf(data = df_AI, 
                                DV = "Moral_Motivation_Comparison", IV = "Level", 
                                labeliv = "Level", labeldv = "Moral Motivation (Comparison)")

kable(moral_motivation_AI, format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
moral_motivation_human <- welch.t.test.bf(data = df_human, 
                                DV = "Moral_Motivation_Comparison", IV = "Level", 
                                labeliv = "Level", labeldv = "Moral Motivation (Comparison)")

kable(moral_motivation_human, format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

Above we looked at the difference between high and low intelligence for humans and AI separately, here we are looking at the difference between human and AI for high and low separately.

```{r}
simple_effect_low <- welch.t.test.bf(data = df_low, 
                                     DV = "Moral_Motivation_Comparison", IV = "Agent", 
                                     labeliv = "Agent", labeldv = "Moral Motivation (Comparison)")

kable(simple_effect_low, format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
simple_effect_high <- welch.t.test.bf(data = df_high, DV = "Moral_Motivation_Comparison", IV = "Agent", 
                                      labeliv = "Agent", labeldv = "Moral Motivation (Comparison)")

kable(simple_effect_high, format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

We'll then make the figure that we will combine and show in a minute.

```{r, fig.height=4, fig.width=4}
# Fit the model
model <- lm(Moral_Motivation_Comparison ~ Level * Agent, data = df) # model
emm <- emmeans(model, ~ Level * Agent) # Estimated marginal means
emm_df <- as.data.frame(emm) # Convert to data frame for plotting

# Define consistent colors
fill_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")
line_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")

# Ensure correct factor order
df$Level <- factor(df$Level, levels = c("Low Intelligence", "High Intelligence"))
emm_df$Level <- factor(emm_df$Level, levels = c("Low Intelligence", "High Intelligence"))

# Create the plot
moral_motivation_comparison_plot <- ggplot() +

  # Jittered individual data points (filled circles, no outline)
geom_jitter(
  data = df,
  aes(x = Level, y = Moral_Motivation_Comparison, fill = Agent),
  shape = 21,
  size = 2,
  stroke = 0.1,           # tiny border just to make visible
  color = "gray80",       # light neutral outline
  alpha = 0.15,
  position = position_jitterdodge(dodge.width = 0.7, jitter.width = 0.35, jitter.height = 0.35)
)+
  
  # Reference line for comparison baseline
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray60", linewidth = 0.7) +
  
  # Estimated marginal means with visible outline
geom_pointrange(
  data = emm_df,
  aes(
    x = Level,
    y = emmean,
    ymin = lower.CL,
    ymax = upper.CL,
    group = Agent,
    fill = Agent,
    colour = Agent
  ),
  position = position_dodge(width = 0.7),
  shape = 21,         # Fillable circle
  size = 1.2,         # Thicker CI line
  stroke = 1.2,       # Thicker point border
  fatten = 3,         # Large mean point
  show.legend = TRUE
)+
  

  # Color scales
  scale_color_manual(values = line_colors) +
  scale_fill_manual(values = fill_colors) +

  # Axis labels and limits
  labs(
    title = "Perceived Moral Motivation \n from Intelligence Level",
     x = "Intelligence Level",
     y = expression(atop("Moral Motivation", "(Comparison to Average Person)")),
    fill = NULL,
    colour = NULL
  ) +
  coord_cartesian(ylim = c(-3, 3)) +
  scale_y_continuous(breaks = -3:3) +

  # Theme and legend styling
  theme_classic() +
  theme(
    text = element_text(size = 12),
    axis.title = element_text(size = 13),
    axis.text = element_text(size = 12),
    axis.title.y = element_text(margin = margin(r = 10)),
    axis.title.x = element_blank(),
    plot.title = element_text(size = 12, hjust = 0.5, margin = margin(b=10)),  # Centered title
    legend.position = "bottom",
    legend.direction = "horizontal",
    legend.justification = "center",
    legend.box.margin = margin(t = -5),
    legend.key.height = unit(1.2, "lines"),
    legend.key.width = unit(1.2, "lines"),
    legend.text = element_text(size = 12)
  )

moral_motivation_comparison_plot

```


## Trust

```{r, message=FALSE, warning=FALSE}
# Compute model
contrasts(df$Level) <- contr.sum
contrasts(df$Agent) <- contr.sum
model <- lm(Trust ~ Level * Agent, data = df)

# Extract ANOVA into table
model <- car::Anova(model, type = 3)

# Get effect size
eta <- eta_squared(model, partial = TRUE)

# Get tidy ANOVA
anova_df <- as.data.frame(model)

# Remove intercept row
anova_df <- anova_df[-1, ]

# Rename rows from ANOVA table
anova_df <- anova_df %>%
  rownames_to_column("Term") %>%
  rename(
    SS = `Sum Sq`,
    df = Df,
    F = `F value`,
    p = `Pr(>F)`
  )

# Combine with partial eta square
combined_table <- left_join(anova_df, eta, by = c("Term" = "Parameter"))

# Select ones we want for APA and rename
final_table <- combined_table %>% 
  select(Term, df, F, p, Eta2_partial) %>% 
  rename(
    `ηp²` = Eta2_partial
  )

# Format test results

final_table <- final_table %>%
  mutate(
    F = round(F, 2),
    `ηp²` = round(`ηp²`, 2),
    p = case_when(
      is.na(p) ~ NA_character_,
      as.numeric(p) < 0.001 ~ "<.001",
      TRUE ~ sprintf("%.3f", as.numeric(p))
    )
  )

# Rename the rows 
final_table <- final_table %>%
  mutate(
    Term = case_when(
      Term == "Level" ~ "Level",
      Term == "Agent" ~ "Agent",
      Term == "Level:Agent" ~ "Level × Agent",
      TRUE ~ Term
    )
  )


kable(final_table, 
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Trust by Intelligence Level and Agent Type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
trust_table <- df %>%
  group_by(Agent, Level) %>%
  summarise(
    "Mean Trust" = mean(Trust),
    "SD" = sd(Trust),
    n = n(),
    .groups = "drop"
  )

kable(trust_table,
      format = "html", digits = 2,
      caption = "<span style='color:black; font-weight:bold;
      '>Trust by Intelligence Level and Agent Type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

We can break down the interaction effect in the same we have before.

We can first, just so it's all in the same place, look at differences between high and low intelligence on ratings of trust for humans and AI seperately.

```{r}
trust_AI <- welch.t.test.bf(data = df_AI, 
                                DV = "Trust", IV = "Level", 
                                labeliv = "Level", labeldv = "Trust")

kable(trust_AI, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Trust by Intelligence Level (AI Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
trust_human <- welch.t.test.bf(data = df_human, 
                                DV = "Trust", IV = "Level", 
                                labeliv = "Level", labeldv = "Trust")

kable(trust_human, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Trust by Intelligence Level (Human Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

Above we looked at the difference between high and low intelligence for humans and AI separately, here we are looking at the difference between human and AI for high and low separately.

```{r}
simple_effect_low <- welch.t.test.bf(data = df_low, 
                                     DV = "Trust", IV = "Agent", 
                                     labeliv = "Agent", labeldv = "Trust")

kable(simple_effect_low,
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Trust by Agent Type (Low Intelligence Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
simple_effect_high <- welch.t.test.bf(data = df_high, 
                                      DV = "Trust", IV = "Agent", 
                                      labeliv = "Agent", labeldv = "Trust")

kable(simple_effect_high, 
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>Trust by Agent Type (High Intelligence Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r, fig.height=4, fig.width=4}
# Fit the model
model <- lm(Trust ~ Level * Agent, data = df) # model
emm <- emmeans(model, ~ Level * Agent) # Estimated marginal means
emm_df <- as.data.frame(emm) # Convert to data frame for plotting

# Define consistent colors
fill_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")
line_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")

# Ensure correct factor order
df$Level <- factor(df$Level, levels = c("Low Intelligence", "High Intelligence"))
emm_df$Level <- factor(emm_df$Level, levels = c("Low Intelligence", "High Intelligence"))

# Create the plot
trust_plot <- ggplot() +

  # Jittered individual data points (filled circles, no outline)
geom_jitter(
  data = df,
  aes(x = Level, y = Trust, fill = Agent),
  shape = 21,
  size = 2,
  stroke = 0.1,           # tiny border just to make visible
  color = "gray80",       # light neutral outline
  alpha = 0.15,
  position = position_jitterdodge(dodge.width = 0.7, jitter.width = 0.35, jitter.height = 0.35)
)+
  
  # Estimated marginal means with visible outline
geom_pointrange(
  data = emm_df,
  aes(
    x = Level,
    y = emmean,
    ymin = lower.CL,
    ymax = upper.CL,
    group = Agent,
    fill = Agent,
    colour = Agent
  ),
  position = position_dodge(width = 0.7),
  shape = 21,         # Fillable circle
  size = 1.2,         # Thicker CI line
  stroke = 1.2,       # Thicker point border
  fatten = 3,         # Large mean point
  show.legend = TRUE
)+
  

  # Color scales
  scale_color_manual(values = line_colors) +
  scale_fill_manual(values = fill_colors) +

  # Axis labels and limits
  labs(
    title = "Perceived Trustworthiness \n from Intelligence Level",
    x = "Intelligence Level",
    y = "Trustworthiness",
    fill = NULL,
    colour = NULL
  ) +
  coord_cartesian(ylim = c(1, 7)) +
  scale_y_continuous(breaks = 1:7) +

  # Theme and legend styling
  theme_classic() +
  theme(
    text = element_text(size = 12),
    axis.title = element_text(size = 13),
    axis.text = element_text(size = 12),
    axis.title.y = element_text(margin = margin(r = 10)),
    axis.title.x = element_blank(),
    plot.title = element_text(size = 12, hjust = 0.5, margin = margin(b=10)),  # Centered title
    legend.position = "bottom",
    legend.direction = "horizontal",
    legend.justification = "center",
    legend.box.margin = margin(t = -5),
    legend.key.height = unit(1.2, "lines"),
    legend.key.width = unit(1.2, "lines"),
    legend.text = element_text(size = 12)
  )

# Define the subfolder name for figure saving
folder <- "figures"

# Create the folder if it doesn't already exist
if (!dir.exists(folder)) {
  dir.create(folder)
}

# Save
ggsave((file.path(folder, "Study 5 Trust.png")), plot = trust_plot,
       width = 4, height = 4, units = "in", dpi = 300)

trust_plot

```


***

## Danger

```{r, message=FALSE, warning=FALSE}
# Compute model
contrasts(df$Level) <- contr.sum
contrasts(df$Agent) <- contr.sum
model <- lm(Danger ~ Level * Agent, data = df)

# Extract ANOVA into table
model <- car::Anova(model, type = 3)

# Get effect size
eta <- eta_squared(model, partial = TRUE)

# Get tidy ANOVA
anova_df <- as.data.frame(model)

# Remove intercept row
anova_df <- anova_df[-1, ]

# Rename rows from ANOVA table
anova_df <- anova_df %>%
  rownames_to_column("Term") %>%
  rename(
    SS = `Sum Sq`,
    df = Df,
    F = `F value`,
    p = `Pr(>F)`
  )

# Combine with partial eta square
combined_table <- left_join(anova_df, eta, by = c("Term" = "Parameter"))

# Select ones we want for APA and rename
final_table <- combined_table %>% 
  select(Term, df, F, p, Eta2_partial) %>% 
  rename(
    `ηp²` = Eta2_partial
  )

# Format test results

final_table <- final_table %>%
  mutate(
    F = round(F, 2),
    `ηp²` = round(`ηp²`, 2),
    p = case_when(
      is.na(p) ~ NA_character_,
      as.numeric(p) < 0.001 ~ "<.001",
      TRUE ~ sprintf("%.3f", as.numeric(p))
    )
  )

# Rename the rows 
final_table <- final_table %>%
  mutate(
    Term = case_when(
      Term == "Level" ~ "Level",
      Term == "Agent" ~ "Agent",
      Term == "Level:Agent" ~ "Level × Agent",
      TRUE ~ Term
    )
  )


kable(final_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Danger by Intelligence Level and Agent Type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r}
danger_table <- df %>%
  group_by(Agent, Level) %>%
  summarise(
    "Mean Danger" = mean(Danger),
    "SD" = sd(Danger),
    n = n(),
    .groups = "drop"
  )

kable(danger_table, 
      format = "html", digits = 2,
      caption = "<span style='color:black; font-weight:bold;
      '>Danger by Intelligence Level and Agent Type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

```{r, fig.height=4, fig.width=4}
# Fit the model
model <- lm(Danger ~ Level * Agent, data = df) # model
emm <- emmeans(model, ~ Level * Agent) # Estimated marginal means
emm_df <- as.data.frame(emm) # Convert to data frame for plotting

# Define consistent colors
fill_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")
line_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")

# Ensure correct factor order
df$Level <- factor(df$Level, levels = c("Low Intelligence", "High Intelligence"))
emm_df$Level <- factor(emm_df$Level, levels = c("Low Intelligence", "High Intelligence"))

# Create the plot
danger_plot <- ggplot() +

  # Jittered individual data points (filled circles, no outline)
geom_jitter(
  data = df,
  aes(x = Level, y = Danger, fill = Agent),
  shape = 21,
  size = 2,
  stroke = 0.1,           # tiny border just to make visible
  color = "gray80",       # light neutral outline
  alpha = 0.15,
  position = position_jitterdodge(dodge.width = 0.7, jitter.width = 0.35, jitter.height = 0.35)
)+
  
  # Estimated marginal means with visible outline
geom_pointrange(
  data = emm_df,
  aes(
    x = Level,
    y = emmean,
    ymin = lower.CL,
    ymax = upper.CL,
    group = Agent,
    fill = Agent,
    colour = Agent
  ),
  position = position_dodge(width = 0.7),
  shape = 21,         # Fillable circle
  size = 1.2,         # Thicker CI line
  stroke = 1.2,       # Thicker point border
  fatten = 3,         # Large mean point
  show.legend = TRUE
)+
  

  # Color scales
  scale_color_manual(values = line_colors) +
  scale_fill_manual(values = fill_colors) +

  # Axis labels and limits
  labs(
   title = "Perceived Danger \n from Intelligence Level",
    x = "Intelligence Level",
    y = "Danger",
    fill = NULL,
    colour = NULL
  ) +
  coord_cartesian(ylim = c(1, 7)) +
  scale_y_continuous(breaks = 1:7) +

  # Theme and legend styling
  theme_classic() +
  theme(
    text = element_text(size = 12),
    axis.title = element_text(size = 13),
    axis.text = element_text(size = 12),
    axis.title.y = element_text(margin = margin(r = 10)),
    axis.title.x = element_blank(),
    plot.title = element_text(size = 12, hjust = 0.5, margin = margin(b=10)),  # Centered title
    legend.position = "bottom",
    legend.direction = "horizontal",
    legend.justification = "center",
    legend.box.margin = margin(t = -5),
    legend.key.height = unit(1.2, "lines"),
    legend.key.width = unit(1.2, "lines"),
    legend.text = element_text(size = 12)
  )

# Define the subfolder name for figure saving
folder <- "figures"

# Create the folder if it doesn't already exist
if (!dir.exists(folder)) {
  dir.create(folder)
}

# Save
ggsave((file.path(folder, "Study 5 Danger.png")), plot = danger_plot,
       width = 4, height = 4, units = "in", dpi = 300)

danger_plot

```

***

```{r, fig.height=4, fig.width=7}
# Remove legend from the first plot
trust_plot_clean <- trust_plot +
  theme(legend.position = "none")

# Combine
trust_danger_plot <- trust_plot_clean + danger_plot +
  plot_layout(ncol = 2, guides = "collect") &
  theme(legend.position = "bottom")

# Define the subfolder name
folder <- "figures"

# Create the folder if it doesn't already exist
if (!dir.exists(folder)) {
  dir.create(folder)
}

# Save both versions
ggsave((file.path(folder, "Study 5 Moral Trust and Danger.png")), plot = trust_danger_plot,
       width = 7, height = 4, units = "in", dpi = 300)

trust_danger_plot

```

***

# Mixed Model with Moral Motivation and Competence

***

## General Ratings

We have measured both moral motivation and moral competence, and we can plot both side-by-side here below. 

Then, as an exploratory analysis, we'll analyse whether manipulated high vs low intelligence leads to a stronger effect on moral competence than moral motivation (or vice versa), and whether this differs by agent.

***

```{r, fig.height=4, fig.width=7}
# Remove legend from the first plot
moralcompetence_plot_clean <- moralcompetence_plot +
  theme(legend.position = "none")

# Combine
combined_morality_plot <- moralcompetence_plot_clean + moralmotivation_plot +
  plot_layout(ncol = 2, guides = "collect") &
  theme(legend.position = "bottom")

# Define the subfolder name
folder <- "figures"

# Create the folder if it doesn't already exist
if (!dir.exists(folder)) {
  dir.create(folder)
}

# Save both versions
ggsave((file.path(folder, "Study 5 Moral Competence and Motivation.png")), plot = combined_morality_plot,
       width = 7, height = 4, units = "in", dpi = 300)

combined_morality_plot

```

***

Now we'll do an analysis looking at the interactive effect of manipulated agent, described intelligence level, and ratings on the trait type (moral motivation vs. competence). This essentially treats trait type as an additional observed factor, since participants answer both.

```{r}
# Create model for preparation
df_long <- df %>%
  pivot_longer(
    cols = c(Moral_Competence, Moral_Motivation),
    names_to = "Outcome",
    values_to = "Rating")  %>%
  mutate(
    Outcome = factor(Outcome, levels = c("Moral_Competence", "Moral_Motivation")),
    Agent = factor(Agent, levels = c("Human", "AI")),
    Level = factor(Level, levels = c("Low Intelligence", "High Intelligence"))
  )

# Set contrasts
contrasts(df_long$Agent) <- contr.treatment
contrasts(df_long$Level) <- contr.treatment
contrasts(df_long$Outcome) <- contr.treatment

# Model with random intercept by participant and slope for trait/outcome type (Does not converge)
#model <- lmer(
 #Rating ~ Outcome * Agent * Level + (1 + Outcome | Participant),
 #data = df_long
#)


# Model with random intercept by participant
model <- lmer(
  Rating ~ Outcome * Level * Agent + ((1 | Participant)),
  data = df_long
)

# Tidy and format results
formatted_table <- broom.mixed::tidy(model, effects = "fixed") %>%
  mutate(
    Term = case_when(
      # Intercept
      term == "(Intercept)" ~ "Intercept",

      # Main effects
      term == "OutcomeMoral_Motivation" ~ "Moral Motivation vs Competence [Motivation]",
      term == "LevelHigh Intelligence" ~ "Intelligence Level [High]",
      term == "AgentAI" ~ "Agent [AI]",
      

      # Two-way interactions
      term == "OutcomeMoral_Motivation:LevelHigh Intelligence" ~ "Intelligence Level × Moral Trait",
      term == "OutcomeMoral_Motivation:AgentAI" ~ "Agent × Moral Trait",
      term == "LevelHigh Intelligence:AgentAI" ~ "Intelligence Level × Agent",
      
      # three-way interactions
      term == "OutcomeMoral_Motivation:LevelHigh Intelligence:AgentAI" ~ "Intelligence Level × Agent x Moral Trait",

      # Fallback
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = round(df, 1),
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    )
  ) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,       
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>The interactive effect of agent type, intelligence level and trait type (moral motivation vs competence) on ratings </span>",
      row.names = FALSE) %>%
      kable_styling(bootstrap_options = "striped",full_width = FALSE, position = "left")
```


We can see there is a 3-way interaction so we can explore that. 

***

We'll first split by agent type.

```{r}
# We'll first break down the dataframe by agent type (but in the long format)
df_long_AI <- df_long %>% filter(Agent == "AI")

# Fit the model
model_AI <- lmer(Rating ~ Outcome * Level + (1 | Participant), data = df_long_AI)

# Tidy and format results
formatted_table <- broom.mixed::tidy(model_AI, effects = "fixed") %>%
  mutate(
    Term = case_when(
      # Intercept
      term == "(Intercept)" ~ "Intercept",

      # Main effects
      term == "OutcomeMoral_Motivation" ~ "Moral Motivation vs Competence [Motivation]",
      term == "LevelHigh Intelligence" ~ "Intelligence Level [High]",
      
      # Two-way interactions
      term == "OutcomeMoral_Motivation:LevelHigh Intelligence" ~ "Intelligence Level × Moral Trait",

      # Fallback
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = round(df, 1),
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    )
  ) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,       
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>The interactive effect of intelligence level and trait type (moral motivation vs competence) on ratings (AI Only) </span>",
      row.names = FALSE) %>%
      kable_styling(bootstrap_options = "striped",full_width = FALSE, position = "left")
```


```{r}
# We'll first break down the dataframe by agent type (but in the long format)
df_long_human <- df_long %>% filter(Agent == "Human")

# Fit the model
model_human <- lmer(Rating ~ Outcome * Level + (1 | Participant), data = df_long_human)

# Tidy and format results
formatted_table <- broom.mixed::tidy(model_human, effects = "fixed") %>%
  mutate(
    Term = case_when(
      # Intercept
      term == "(Intercept)" ~ "Intercept",

      # Main effects
      term == "OutcomeMoral_Motivation" ~ "Moral Motivation vs Competence [Motivation]",
      term == "LevelHigh Intelligence" ~ "Intelligence Level [High]",
      
      # Two-way interactions
      term == "OutcomeMoral_Motivation:LevelHigh Intelligence" ~ "Intelligence Level × Moral Trait",

      # Fallback
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = round(df, 1),
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    )
  ) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,       
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>The interactive effect of intelligence level and trait type (moral motivation vs competence) on ratings (Human Only) </span>",
      row.names = FALSE) %>%
      kable_styling(bootstrap_options = "striped",full_width = FALSE, position = "left")
```

***

We'll split by level type.

```{r}
# We'll first break down the dataframe by level (but in the long format)
df_long_low <- df_long %>% filter(Level == "Low Intelligence")

# Fit the model
model_low <- lmer(Rating ~ Outcome * Agent + (1 | Participant), data = df_long_low)

# Tidy and format results
formatted_table <- broom.mixed::tidy(model_low, effects = "fixed") %>%
  mutate(
    Term = case_when(
      # Intercept
      term == "(Intercept)" ~ "Intercept",

      # Main effects
      term == "OutcomeMoral_Motivation" ~ "Moral Motivation vs Competence [Motivation]",
      term == "AgentAI" ~ "Agent [AI]",
      
      # Two-way interactions
      term == "OutcomeMoral_Motivation:AgentAI" ~ "Agent × Moral Trait",

      # Fallback
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = round(df, 1),
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    )
  ) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,       
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>The interactive effect of agent and trait type (moral motivation vs competence) on ratings (Low intelligence only) </span>",
      row.names = FALSE) %>%
      kable_styling(bootstrap_options = "striped",full_width = FALSE, position = "left")
```

```{r}
# We'll first break down the dataframe by level (but in the long format)
df_long_high <- df_long %>% filter(Level == "High Intelligence")

# Fit the model
model_high <- lmer(Rating ~ Outcome * Agent + (1 | Participant), data = df_long_high)

# Tidy and format results
formatted_table <- broom.mixed::tidy(model_high, effects = "fixed") %>%
  mutate(
    Term = case_when(
      # Intercept
      term == "(Intercept)" ~ "Intercept",

      # Main effects
      term == "OutcomeMoral_Motivation" ~ "Moral Motivation vs Competence [Motivation]",
      term == "AgentAI" ~ "Agent [AI]",
      
      # Two-way interactions
      term == "OutcomeMoral_Motivation:AgentAI" ~ "Agent × Moral Trait",

      # Fallback
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = round(df, 1),
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    )
  ) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,       
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>The interactive effect of agent and trait type (moral motivation vs competence) on ratings (High intelligence only) </span>",
      row.names = FALSE) %>%
      kable_styling(bootstrap_options = "striped",full_width = FALSE, position = "left")
```

***

## Comparison Question

We'll turn to the question in comparison to the average person, just create a combined figure for moral motivation and moral competence in comparison to average person.

```{r, fig.height=4, fig.width=8}
# Remove legend from the first plot
moral_competence_comparison_plot_clean <- moral_competence_comparison_plot +
  theme(legend.position = "none")

# Combine
combined_morality_comparison_plot <- moral_competence_comparison_plot_clean + moral_motivation_comparison_plot +
  plot_layout(ncol = 2, guides = "collect") &
  theme(legend.position = "bottom")

# Define the subfolder name
folder <- "figures"

# Create the folder if it doesn't already exist
if (!dir.exists(folder)) {
  dir.create(folder)
}

# Save both versions
ggsave((file.path(folder, "Study 5 Moral Competence and Motivation Comparison.png")), plot = combined_morality_comparison_plot,
       width = 8, height = 4, units = "in", dpi = 300)

combined_morality_comparison_plot

```

***

Now we'll do an analysis looking at the interactive effect of manipulated agent, described intelligence level, and ratings on the trait type (moral motivation vs. competence) for the comparison questions. Again, this essentially treats trait type as an additional observed factor, since participants answer both.

```{r}
# Create model for preparation
df_long_comparison <- df %>%
  pivot_longer(
    cols = c(Moral_Competence_Comparison, Moral_Motivation_Comparison),
    names_to = "Outcome",
    values_to = "Rating")  %>%
  mutate(
    Outcome = factor(Outcome, levels = c("Moral_Competence_Comparison", "Moral_Motivation_Comparison")),
    Agent = factor(Agent, levels = c("Human", "AI")),
    Level = factor(Level, levels = c("Low Intelligence", "High Intelligence"))
  )

# Set contrasts
contrasts(df_long_comparison$Agent) <- contr.treatment
contrasts(df_long_comparison$Level) <- contr.treatment
contrasts(df_long_comparison$Outcome) <- contr.treatment

# Model with random intercept by participant
model <- lmer(
  Rating ~ Outcome * Level * Agent + ((1 | Participant)),
  data = df_long_comparison
)

# Tidy and format results
formatted_table <- broom.mixed::tidy(model, effects = "fixed") %>%
  mutate(
    Term = case_when(
      # Intercept
      term == "(Intercept)" ~ "Intercept",

      # Main effects
      term == "OutcomeMoral_Motivation_Comparison" ~ "Moral Motivation vs Competence [Motivation]",
      term == "LevelHigh Intelligence" ~ "Intelligence Level [High]",
      term == "AgentAI" ~ "Agent [AI]",
      

      # Two-way interactions
      term == "OutcomeMoral_Motivation_Comparison:LevelHigh Intelligence" ~ "Intelligence Level × Moral Trait",
      term == "OutcomeMoral_Motivation_Comparison:AgentAI" ~ "Agent × Moral Trait",
      term == "LevelHigh Intelligence:AgentAI" ~ "Intelligence Level × Agent",
      
      # three-way interactions
      term == "OutcomeMoral_Motivation_Comparison:LevelHigh Intelligence:AgentAI" ~ "Intelligence Level × Agent x Moral Trait",

      # Fallback
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = round(df, 1),
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    )
  ) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,       
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>The interactive effect of agent type, intelligence level and trait type (moral motivation vs competence) on ratings in comparison to the average person</span>",
      row.names = FALSE) %>%
      kable_styling(bootstrap_options = "striped",full_width = FALSE, position = "left")
```

***

We can see there is a 3-way interaction so we can explore that. 

***

We'll first split by agent type.

```{r}
# We'll first break down the dataframe by agent type (but in the long format) - first for AI.
df_long_comparison_AI <- df_long_comparison %>% filter(Agent == "AI")

# Fit the model
model_comparison_AI <- lmer(Rating ~ Outcome * Level + (1 | Participant), data = df_long_comparison_AI)

# Tidy and format results
formatted_table <- broom.mixed::tidy(model_comparison_AI, effects = "fixed") %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "OutcomeMoral_Motivation_Comparison" ~ "Moral Motivation vs Competence [Motivation]",
      term == "LevelHigh Intelligence" ~ "Intelligence Level [High]",
      term == "OutcomeMoral_Motivation_Comparison:LevelHigh Intelligence" ~ "Intelligence Level × Moral Trait",

      # Fallback
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = round(df, 1),
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    )
  ) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,       
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>The interactive effect of intelligence level and trait type (moral motivation vs competence) on comparison ratings (AI Only) </span>",
      row.names = FALSE) %>%
      kable_styling(bootstrap_options = "striped",full_width = FALSE, position = "left")
```


```{r}
# We'll first break down the dataframe by agent type (but in the long format) - now for humans.
df_long_comparison_human <- df_long_comparison %>% filter(Agent == "Human")

# Fit the model
model_comparison_human <- lmer(Rating ~ Outcome * Level + (1 | Participant), data = df_long_comparison_human)

# Tidy and format results
formatted_table <- broom.mixed::tidy(model_comparison_human, effects = "fixed") %>%
  mutate(
    Term = case_when(
      # Intercept
      term == "(Intercept)" ~ "Intercept",

      # Main effects
      term == "OutcomeMoral_Motivation" ~ "Moral Motivation vs Competence [Motivation]",
      term == "LevelHigh Intelligence" ~ "Intelligence Level [High]",
      
      # Two-way interactions
      term == "OutcomeMoral_Motivation:LevelHigh Intelligence" ~ "Intelligence Level × Moral Trait",

      # Fallback
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = round(df, 1),
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    )
  ) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,       
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>The interactive effect of intelligence level and trait type (moral motivation vs competence) on comparison ratings (Human Only) </span>",
      row.names = FALSE) %>%
      kable_styling(bootstrap_options = "striped",full_width = FALSE, position = "left")
```

***

We'll split by level type.

```{r}
# We'll first break down the dataframe by level (but in the long format)
df_long_comparison_low <- df_long_comparison %>% filter(Level == "Low Intelligence")

# Fit the model
model_comparison_low <- lmer(Rating ~ Outcome * Agent + (1 | Participant), data = df_long_comparison_low)

# Tidy and format results
formatted_table <- broom.mixed::tidy(model_comparison_low, effects = "fixed") %>%
  mutate(
    Term = case_when(
      # Intercept
      term == "(Intercept)" ~ "Intercept",

      # Main effects
      term == "OutcomeMoral_Motivation" ~ "Moral Motivation vs Competence [Motivation]",
      term == "AgentAI" ~ "Agent [AI]",
      
      # Two-way interactions
      term == "OutcomeMoral_Motivation:AgentAI" ~ "Agent × Moral Trait",

      # Fallback
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = round(df, 1),
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    )
  ) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,       
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>The interactive effect of agent and trait type (moral motivation vs competence) on comparison ratings (Low intelligence only) </span>",
      row.names = FALSE) %>%
      kable_styling(bootstrap_options = "striped",full_width = FALSE, position = "left")
```

```{r}
# We'll first break down the dataframe by level (but in the long format)
df_long_comparison_high <- df_long_comparison %>% filter(Level == "High Intelligence")

# Fit the model
model_comparison_high <- lmer(Rating ~ Outcome * Agent + (1 | Participant), data = df_long_comparison_high)

# Tidy and format results
formatted_table <- broom.mixed::tidy(model_comparison_high, effects = "fixed") %>%
  mutate(
    Term = case_when(
      # Intercept
      term == "(Intercept)" ~ "Intercept",

      # Main effects
      term == "OutcomeMoral_Motivation" ~ "Moral Motivation vs Competence [Motivation]",
      term == "AgentAI" ~ "Agent [AI]",
      
      # Two-way interactions
      term == "OutcomeMoral_Motivation:AgentAI" ~ "Agent × Moral Trait",

      # Fallback
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = round(df, 1),
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    )
  ) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,       
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>The interactive effect of agent and trait type (moral motivation vs competence) on comparison ratings (High intelligence only) </span>",
      row.names = FALSE) %>%
      kable_styling(bootstrap_options = "striped",full_width = FALSE, position = "left")
```

***

# Correlations

***

We'll look, across conditions, the correlation between participants ratings of intelligence and morality. We can use a quick custom function to make this easy.

```{r}
# Individual correlation 
jim.correlation <- function(DV_A, DV_B, Item) {
  
test <- cor.test(DV_A, DV_B, method = "pearson")

correlation <- test$estimate
correlation <- round(correlation, digits = 2)
df_val <- sprintf("%.0f", test$parameter)  # APA style: no decimals for df

p_raw <- test$p.value
p_formatted <- ifelse(
  is.na(p_raw), NA,
  ifelse(p_raw < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p_raw))))
)

combined <- data.frame(
    df = df_val,
    r = correlation,
    p = p_formatted,
    row.names = Item,
    check.names = FALSE
  )

  return(combined)
}

```

***

We first look at the highest level with the correlation between general intelligence, general moral competence, and general moral motivation.

```{r}
intelligence_moral_competence_corr <- jim.correlation(DV_A = df$Intelligent, 
                                              DV_B = df$Moral_Competence,
                                              Item = "Intelligence + Moral Competence")

intelligence_moral_motivation_corr <- jim.correlation(DV_A = df$Intelligent, 
                                              DV_B = df$Moral_Motivation,
                                              Item = "Intelligence + Moral Motivation")

# Bind together
correlation_summary <- bind_rows(
  intelligence_moral_competence_corr,
  intelligence_moral_motivation_corr
)

kable(correlation_summary, format = "html",
            row.names = TRUE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

And the same for the relationship between intelligence compared to a human and morality compared to a human.

```{r}
intelligence_moral_competence_comparison_corr <- jim.correlation(DV_A = df$Intelligent_Comparison, 
                                              DV_B = df$Moral_Competence_Comparison,
                                              Item = "Intelligence (Comparison) + Moral Competence (Comparison)")

intelligence_moral_motivation_comparison_corr <- jim.correlation(DV_A = df$Intelligent_Comparison, 
                                              DV_B = df$Moral_Motivation_Comparison,
                                              Item = "Intelligence (Comparison) + Moral Motivation (Comparison)")

# Bind together
correlation_summary <- bind_rows(
  intelligence_moral_competence_comparison_corr,
  intelligence_moral_motivation_comparison_corr
)

kable(correlation_summary, format = "html",
            row.names = TRUE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

Out of interest we'll also look at this main correlations broken down by conditions.

```{r}
# Low intelligence, AI agent
intelligence_moral_competence_low_AI <- jim.correlation(DV_A = df_low_intelligence_AI$Intelligent, 
                                              DV_B = df_low_intelligence_AI$Moral_Competence,
                                              Item = "Intelligence + Moral Competence (AI + Low Intelligence)")

intelligence_moral_motivation_low_AI <- jim.correlation(DV_A = df_low_intelligence_AI$Intelligent, 
                                              DV_B = df_low_intelligence_AI$Moral_Motivation,
                                              Item = "Intelligence + Moral Motivation (AI + Low Intelligence)")
# High intelligence, AI agent
intelligence_moral_competence_high_AI <- jim.correlation(DV_A = df_high_intelligence_AI$Intelligent, 
                                              DV_B = df_high_intelligence_AI$Moral_Competence,
                                              Item = "Intelligence + Moral Competence (AI + High Intelligence)")

intelligence_moral_motivation_high_AI <- jim.correlation(DV_A = df_high_intelligence_AI$Intelligent, 
                                              DV_B = df_high_intelligence_AI$Moral_Motivation,
                                              Item = "Intelligence + Moral Motivation (AI + High Intelligence)")

# Low intelligence, Human agent
intelligence_moral_competence_low_human <- jim.correlation(DV_A = df_low_intelligence_human$Intelligent, 
                                              DV_B = df_low_intelligence_human$Moral_Competence,
                                              Item = "Intelligence + Moral Competence (Human + Low Intelligence)")

intelligence_moral_motivation_low_human <- jim.correlation(DV_A = df_low_intelligence_human$Intelligent, 
                                              DV_B = df_low_intelligence_human$Moral_Motivation,
                                              Item = "Intelligence + Moral Motivation (Human + Low Intelligence)")

# High intelligence, AI agent
intelligence_moral_competence_high_human <- jim.correlation(DV_A = df_high_intelligence_human$Intelligent, 
                                              DV_B = df_high_intelligence_human$Moral_Competence,
                                              Item = "Intelligence + Moral Competence (Human + High Intelligence)")

intelligence_moral_motivation_high_human <- jim.correlation(DV_A = df_high_intelligence_human$Intelligent, 
                                              DV_B = df_high_intelligence_human$Moral_Motivation,
                                              Item = "Intelligence + Moral Motivation (Human + High Intelligence)")

# Bind together
correlation_summary <- bind_rows(
intelligence_moral_competence_low_AI,
intelligence_moral_motivation_low_AI,
intelligence_moral_competence_high_AI,
intelligence_moral_motivation_high_AI,
intelligence_moral_competence_low_human,
intelligence_moral_motivation_low_human,
intelligence_moral_competence_high_human,
intelligence_moral_motivation_high_human
)

kable(correlation_summary, format = "html",
            row.names = TRUE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```

***

# Familiarity

***

Just as an exploratory test, we can look at whether familiarity influences these results. This is the distribution of familiarity scores.

```{r, fig.width=4, fig.height=4}
ggplot(df, aes(x = Familiarity)) +
  geom_histogram(binwidth = 1, fill = "#0072B2", color = "white") +
  scale_x_continuous(breaks = 0:6) +
  labs(
    title = "Distribution of Familiarity Ratings",
    x = "Familiarity",
    y = "Number of Participants"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5)
  )
```

***

## Intelligence

We'll look at the effects of familiarity, intelligence level (high vs low), and agent (human vs AI) on ratings of intelligence.

```{r, message=FALSE}
# Centre familiarity
df <- df %>%
  mutate(
    Familiarity_c = scale(Familiarity, center = TRUE, scale = FALSE) %>% as.numeric(),
    Level = factor(Level, levels = c("Low Intelligence", "High Intelligence")),
    Agent = factor(Agent, levels = c("Human", "AI"))
    )
                   
# Set contrasts
contrasts(df$Level) <- contr.treatment
contrasts(df$Agent) <- contr.treatment

# Fit model
model <- lm(Intelligent ~ Familiarity_c * Level * Agent, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Familiarity_c" ~ "Familiarity (Centred)",
      term == "LevelHigh Intelligence" ~ "Level [High Intelligence]",
      term == "AgentAI" ~ "Agent [AI]",
      term == "Familiarity_c:LevelHigh Intelligence" ~ "Familiarity × Intelligence Level",
      term == "Familiarity_c:AgentAI" ~ "Familiarity × Agent",
      term == "LevelHigh Intelligence:AgentAI" ~ "Intelligence Level × Agent",
      term == "Familiarity_c:LevelHigh Intelligence:AgentAI" ~ "Familiarity x Intelligence Level × Agent",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "Familiarity (Centred)", 
      "Level [High Intelligence]", 
      "Agent [AI]",
      "Intelligence Level × Agent",
      "Familiarity × Intelligence Level",
      "Familiarity × Agent",
      "Familiarity x Intelligence Level × Agent"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived intelligence by participant AI familiarity, manipulated intelligence level, and agent type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```

***

## Moral Competence

We'll look at the effects of familiarity, intelligence level (high vs low), and agent (human vs AI) on ratings of moral competence.

```{r, message=FALSE}
# Centre familiarity
df <- df %>%
  mutate(
    Familiarity_c = scale(Familiarity, center = TRUE, scale = FALSE) %>% as.numeric(),
    Level = factor(Level, levels = c("Low Intelligence", "High Intelligence")),
    Agent = factor(Agent, levels = c("Human", "AI"))
    )
                   
# Set contrasts
contrasts(df$Level) <- contr.treatment
contrasts(df$Agent) <- contr.treatment

# Fit model
model <- lm(Moral_Competence ~ Familiarity_c * Level * Agent, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Familiarity_c" ~ "Familiarity (Centred)",
      term == "LevelHigh Intelligence" ~ "Level [High Intelligence]",
      term == "AgentAI" ~ "Agent [AI]",
      term == "Familiarity_c:LevelHigh Intelligence" ~ "Familiarity × Intelligence Level",
      term == "Familiarity_c:AgentAI" ~ "Familiarity × Agent",
      term == "LevelHigh Intelligence:AgentAI" ~ "Intelligence Level × Agent",
      term == "Familiarity_c:LevelHigh Intelligence:AgentAI" ~ "Familiarity x Intelligence Level × Agent",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "Familiarity (Centred)", 
      "Level [High Intelligence]", 
      "Agent [AI]",
      "Intelligence Level × Agent",
      "Familiarity × Intelligence Level",
      "Familiarity × Agent",
      "Familiarity x Intelligence Level × Agent"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived moral competence by participant AI familiarity, manipulated intelligence level, and agent type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```

***

## Moral Competence

We'll look at the effects of familiarity, intelligence level (high vs low), and agent (human vs AI) on ratings of moral competence.

```{r, message=FALSE}
# Centre familiarity
df <- df %>%
  mutate(
    Familiarity_c = scale(Familiarity, center = TRUE, scale = FALSE) %>% as.numeric(),
    Level = factor(Level, levels = c("Low Intelligence", "High Intelligence")),
    Agent = factor(Agent, levels = c("Human", "AI"))
    )
                   
# Set contrasts
contrasts(df$Level) <- contr.treatment
contrasts(df$Agent) <- contr.treatment

# Fit model
model <- lm(Moral_Motivation ~ Familiarity_c * Level * Agent, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Familiarity_c" ~ "Familiarity (Centred)",
      term == "LevelHigh Intelligence" ~ "Level [High Intelligence]",
      term == "AgentAI" ~ "Agent [AI]",
      term == "Familiarity_c:LevelHigh Intelligence" ~ "Familiarity × Intelligence Level",
      term == "Familiarity_c:AgentAI" ~ "Familiarity × Agent",
      term == "LevelHigh Intelligence:AgentAI" ~ "Intelligence Level × Agent",
      term == "Familiarity_c:LevelHigh Intelligence:AgentAI" ~ "Familiarity x Intelligence Level × Agent",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "Familiarity (Centred)", 
      "Level [High Intelligence]", 
      "Agent [AI]",
      "Intelligence Level × Agent",
      "Familiarity × Intelligence Level",
      "Familiarity × Agent",
      "Familiarity x Intelligence Level × Agent"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived moral motivation by participant AI familiarity, manipulated intelligence level, and agent type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```


***

# AI Accuracy (PEW)

Now we look at the questions where participants were given different questions about AI taken from PEW, to get a more "objective" measure of AI knowledge to complement the self-report familiarity measure. 

***

We can first just look at the distributions.

```{r}
# Create summary table
pew_summary <- df %>%
  count(Pew_Correct) %>%
  mutate(
    Pew_Correct = ifelse(is.na(Pew_Correct), "NA", as.character(Pew_Correct)),
    Percent = round(100 * n / sum(n), 1)
  )

# Show summary
kable(pew_summary, format = "html", col.names = c("Pew_Correct Score", "Count", "Percent")) %>%
  kable_styling(
    bootstrap_options = c("striped"),
    full_width = FALSE,
    position = "left"
  )
```

```{r, message = FALSE}
ggplot(df, aes(x = Pew_Correct)) +
  geom_histogram(binwidth = 1, fill = "#0072B2", color = "white") +
  scale_x_continuous(breaks = 0:6) +
  labs(
    title = "Distribution of Pew AI Knowledge Scores",
    x = "Pew_Correct Score (0–6)",
    y = "Number of Participants"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5)
  )
```

***

## Intelligence

We'll look at the effects of familiarity, intelligence level (high vs low), and agent (human vs AI) on ratings of intelligence.

```{r, message=FALSE}
# Centre PEW
df <- df %>%
  mutate(
    Pew_Correct_c = scale(Pew_Correct, center = TRUE, scale = FALSE) %>% as.numeric(),
    Level = factor(Level, levels = c("Low Intelligence", "High Intelligence")),
    Agent = factor(Agent, levels = c("Human", "AI"))
    )
                   
# Set contrasts
contrasts(df$Level) <- contr.treatment
contrasts(df$Agent) <- contr.treatment

# Fit model
model <- lm(Intelligent ~ Pew_Correct_c * Level * Agent, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Pew_Correct_c" ~ "PEW AI Knowledge (Centred)",
      term == "LevelHigh Intelligence" ~ "Level [High Intelligence]",
      term == "AgentAI" ~ "Agent [AI]",
      term == "Pew_Correct_c:LevelHigh Intelligence" ~ "PEW × Intelligence Level",
      term == "Pew_Correct_c:AgentAI" ~ "PEW × Agent",
      term == "LevelHigh Intelligence:AgentAI" ~ "Intelligence Level × Agent",
      term == "Pew_Correct_c:LevelHigh Intelligence:AgentAI" ~ "PEW x Intelligence Level × Agent",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "PEW AI Knowledge (Centred)", 
      "Level [High Intelligence]", 
      "Agent [AI]",
      "Intelligence Level × Agent",
      "PEW × Intelligence Level",
      "PEW × Agent",
      "PEW x Intelligence Level × Agent"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived intelligence by participant AI knowledge (PEW), manipulated intelligence level, and agent type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```

***

## Moral Competence

```{r, message=FALSE}
# Centre PEW
df <- df %>%
  mutate(
    Pew_Correct_c = scale(Pew_Correct, center = TRUE, scale = FALSE) %>% as.numeric(),
    Level = factor(Level, levels = c("Low Intelligence", "High Intelligence")),
    Agent = factor(Agent, levels = c("Human", "AI"))
    )
                   
# Set contrasts
contrasts(df$Level) <- contr.treatment
contrasts(df$Agent) <- contr.treatment

# Fit model
model <- lm(Moral_Competence ~ Pew_Correct_c * Level * Agent, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Pew_Correct_c" ~ "PEW AI Knowledge (Centred)",
      term == "LevelHigh Intelligence" ~ "Level [High Intelligence]",
      term == "AgentAI" ~ "Agent [AI]",
      term == "Pew_Correct_c:LevelHigh Intelligence" ~ "PEW × Intelligence Level",
      term == "Pew_Correct_c:AgentAI" ~ "PEW × Agent",
      term == "LevelHigh Intelligence:AgentAI" ~ "Intelligence Level × Agent",
      term == "Pew_Correct_c:LevelHigh Intelligence:AgentAI" ~ "PEW x Intelligence Level × Agent",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "PEW AI Knowledge (Centred)", 
      "Level [High Intelligence]", 
      "Agent [AI]",
      "Intelligence Level × Agent",
      "PEW × Intelligence Level",
      "PEW × Agent",
      "PEW x Intelligence Level × Agent"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived moral competence by participant AI knowledge (PEW), manipulated intelligence level, and agent type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```

***

## Moral Motivation

```{r, message=FALSE}
# Centre PEW
df <- df %>%
  mutate(
    Pew_Correct_c = scale(Pew_Correct, center = TRUE, scale = FALSE) %>% as.numeric(),
    Level = factor(Level, levels = c("Low Intelligence", "High Intelligence")),
    Agent = factor(Agent, levels = c("Human", "AI"))
    )
                   
# Set contrasts
contrasts(df$Level) <- contr.treatment
contrasts(df$Agent) <- contr.treatment

# Fit model
model <- lm(Moral_Motivation ~ Pew_Correct_c * Level * Agent, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Pew_Correct_c" ~ "PEW AI Knowledge (Centred)",
      term == "LevelHigh Intelligence" ~ "Level [High Intelligence]",
      term == "AgentAI" ~ "Agent [AI]",
      term == "Pew_Correct_c:LevelHigh Intelligence" ~ "PEW × Intelligence Level",
      term == "Pew_Correct_c:AgentAI" ~ "PEW × Agent",
      term == "LevelHigh Intelligence:AgentAI" ~ "Intelligence Level × Agent",
      term == "Pew_Correct_c:LevelHigh Intelligence:AgentAI" ~ "PEW x Intelligence Level × Agent",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "PEW AI Knowledge (Centred)", 
      "Level [High Intelligence]", 
      "Agent [AI]",
      "Intelligence Level × Agent",
      "PEW × Intelligence Level",
      "PEW × Agent",
      "PEW x Intelligence Level × Agent"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived moral motivation by participant AI knowledge (PEW), manipulated intelligence level, and agent type</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```