knitr::opts_chunk$set(cache=FALSE, fig.retina=2,
                      tidy.opts=list(width.cutoff=120),  # For code
                      options(width=120))  # For output

# Load libraries and data
library(printr)
library(tidyverse)
library(forcats)
library(lavaan)
library(semPlot)
library(pander)
library(ggstance)

source(file.path(PROJHOME, "Analysis", "graphics.R"))


# Load clean data
new.cols <- filter(coef.names, new.column == TRUE)
df.survey <- readRDS(file.path(PROJHOME, "Data", "survey_clean.rds")) %>%
  # Duplicate columns using short names for each of the SEM variables (i.e.
  # create an x2 column from the PPGENDER column)
  mutate_(.dots = setNames(new.cols$coef.name, new.cols$coef.abbr))


# Helpful functions for modeling
sem.model <- function(model.def) {
  sem(model.def, data=df.survey, missing="FIML", fixed.x=FALSE)
}

sem.extract.latent <- function(model.fit) {
  standardizedSolution(model.fit) %>%
    filter(op == "=~")
}

sem.extract.path.coefs <- function(model.fit) {
  standardizedSolution(model.fit) %>%
    filter(op == "~") %>%
    left_join(coef.names, by=c("rhs" = "coef.abbr")) %>%
    mutate(term = sprintf("%s (%s)", coef.clean, rhs)) %>%
    select(term, est.std, se, z, pvalue)
}

SEM results

KKK models

model.reduced.kkk <- '
# Measurement model / latent variables
  # none
# Regressions
  y1k ~ x1 + x2 + x3 + x4k + x5k + x6k + x7k + x8k + x9k
# Residual correlations
  x1 ~~ x2 + x3 + x4k + x5k + x6k + x7k + x8k
  x2 ~~ x3 + x4k + x5k + x6k + x7k + x8k
  x3 ~~ x4k + x5k + x6k + x7k + x8k
  x4k ~~ x5k + x6k + x7k + x8k
  x5k ~~ x6k + x7k + x8k
  x6k ~~ x7k + x8k
  x7k ~~ x8k
'

model.full.kkk <- '
# Measurement model / latent variables
  # none
# Regressions
  y1k ~ x1 + x2 + x3 + x4k + x5k + x6k + x7k + x8k + x9k + x10k + x11k
# Residual correlations
  x1 ~~ x2 + x3 + x4k + x5k + x6k + x7k + x8k + x10k + x11k
  x2 ~~ x3 + x4k + x5k + x6k + x7k + x8k + x10k + x11k
  x3 ~~ x4k + x5k + x6k + x7k + x8k + x10k + x11k
  x4k ~~ x5k + x6k + x7k + x8k + x10k + x11k
  x5k ~~ x6k + x7k + x8k + x10k + x11k
  x6k ~~ x7k + x8k + x10k + x11k
  x7k ~~ x8k + x10k + x11k
  x8k ~~ x10k + x11k
  x10k ~~ x11k
'

kkk.models <- data_frame(model.def = c(model.reduced.kkk, model.full.kkk)) %>%
  mutate(model.fit = model.def %>% map(sem.model),
         model.latent.vars = model.fit %>% map(sem.extract.latent),
         model.path.coefs = model.fit %>% map(sem.extract.path.coefs))
## Found more than one class "Model" in cache; using the first, from namespace 'lavaan'

Coefficient plot

coef.plot.kkk <- bind_rows(kkk.models$model.path.coefs, .id="model.name") %>%
  mutate(low = est.std - se,
         high = est.std + se) %>%
  mutate(model.name = factor(model.name, levels=c(1, 2),
                             labels=c("Reduced    ", "Full"), ordered=TRUE),
         term = fct_rev(fct_inorder(term)))
ggplot(coef.plot.kkk, aes(x=est.std, y=term, colour=model.name)) + 
  geom_vline(xintercept=0, colour="#FF851B") +
  geom_pointrangeh(aes(xmin=low, xmax=high), size=0.5,
                   position=position_dodge(width=0.5)) + 
  scale_colour_manual(values=framing.palette("palette1"), name=NULL) +
  labs(x="Standardized coefficient", y=NULL,
       title="KKK framing experiment",
       subtitle="Standardized coefficients from reduced and full SEM models") +
  theme_framing(12) + theme(legend.position="bottom")

Reduced model

kkk.reduced <- pandoc.table.return(kkk.models$model.path.coefs[[1]],
                                   keep.line.breaks=TRUE,
                                   justify="lcccc")
cat(kkk.reduced)
term est.std se z pvalue
Race (x1) 0.169 0.042 4.01 0
Sex (x2) 0.172 0.041 4.24 0
Party (x3) -0.088 0.042 -2.08 0.038
Frame × openness (x4k) 0.47 0.18 2.62 0.009
Frame × conscientiousness (x5k) -0.65 0.205 -3.16 0.002
Frame × extraversion (x6k) -0.037 0.131 -0.284 0.776
Frame × agreeableness (x7k) 0.387 0.207 1.87 0.061
Frame × neuroticism (x8k) -0.043 0.11 -0.385 0.7
KKK frame (x9k) -0.024 0.265 -0.092 0.927

Full model

kkk.full <- pandoc.table.return(kkk.models$model.path.coefs[[2]],
                                keep.line.breaks=TRUE,
                                justify="lcccc")
cat(kkk.full)
term est.std se z pvalue
Race (x1) 0.141 0.045 3.14 0.002
Sex (x2) 0.137 0.041 3.33 0.001
Party (x3) -0.066 0.041 -1.6 0.109
Frame × openness (x4k) 0.282 0.203 1.38 0.166
Frame × conscientiousness (x5k) -0.61 0.222 -2.74 0.006
Frame × extraversion (x6k) 0.04 0.119 0.339 0.735
Frame × agreeableness (x7k) 0.379 0.179 2.11 0.035
Frame × neuroticism (x8k) -0.039 0.107 -0.368 0.713
KKK frame (x9k) -0.231 0.234 -0.988 0.323
Frame × political knowledge (x10k) 0.317 0.102 3.11 0.002
Frame × need for cognition (x11k) -0.014 0.171 -0.083 0.934

Path diagram (reduced)

semPaths(kkk.models$model.fit[[1]], layout="tree", rotation=2)
## Warning in lavaan(slotOptions = object@Options, slotParTable = object@ParTable, : lavaan WARNING: model has NOT
## converged!

Path diagram (full)

semPaths(kkk.models$model.fit[[2]], layout="tree", rotation=2)
## Warning in lavaan(slotOptions = object@Options, slotParTable = object@ParTable, : lavaan WARNING: model has NOT
## converged!

Gun models

model.reduced.gun <- '
# Measurement model / latent variables
  # none
# Regressions
  y1g ~ x1 + x2 + x3 + x4g + x5g + x6g + x7g + x8g + x9g
# Residual correlations
  x1 ~~ x2 + x3 + x4g + x5g + x6g + x7g + x8g
  x2 ~~ x3 + x4g + x5g + x6g + x7g + x8g
  x3 ~~ x4g + x5g + x6g + x7g + x8g
  x4g ~~ x5g + x6g + x7g + x8g
  x5g ~~ x6g + x7g + x8g
  x6g ~~ x7g + x8g
  x7g ~~ x8g
'

model.full.gun <- '
# Measurement model / latent variables
  # none
# Regressions
  y1g ~ x1 + x2 + x3 + x4g + x5g + x6g + x7g + x8g + x9g + x10g + x11g
# Residual correlations
  x1 ~~ x2 + x3 + x4g + x5g + x6g + x7g + x8g + x10g + x11g
  x2 ~~ x3 + x4g + x5g + x6g + x7g + x8g + x10g + x11g
  x3 ~~ x4g + x5g + x6g + x7g + x8g + x10g + x11g
  x4g ~~ x5g + x6g + x7g + x8g + x10g + x11g
  x5g ~~ x6g + x7g + x8g + x10g + x11g
  x6g ~~ x7g + x8g + x10g + x11g
  x7g ~~ x8g + x10g + x11g
  x8g ~~ x10g + x11g
  x10g ~~ x11g
'

gun.models <- data_frame(model.def = c(model.reduced.gun, model.full.gun)) %>%
  mutate(model.fit = model.def %>% map(sem.model),
         model.latent.vars = model.fit %>% map(sem.extract.latent),
         model.path.coefs = model.fit %>% map(sem.extract.path.coefs))

Coefficient plot

coef.plot.guns <- bind_rows(gun.models$model.path.coefs, .id="model.name") %>%
  mutate(low = est.std - se,
         high = est.std + se) %>%
  mutate(model.name = factor(model.name, levels=c(1, 2),
                             labels=c("Reduced    ", "Full"), ordered=TRUE),
         term = fct_rev(fct_inorder(term)))
ggplot(coef.plot.guns, aes(x=est.std, y=term, colour=model.name)) + 
  geom_vline(xintercept=0, colour="#FF851B") +
  geom_pointrangeh(aes(xmin=low, xmax=high), size=0.5,
                   position=position_dodge(width=0.5)) + 
  scale_colour_manual(values=framing.palette("palette1"), name=NULL) +
  labs(x="Standardized coefficient", y=NULL,
       title="Gun framing experiment",
       subtitle="Standardized coefficients from reduced and full SEM models") +
  theme_framing(12) + theme(legend.position="bottom")

Reduced model

gun.reduced <- pandoc.table.return(gun.models$model.path.coefs[[1]],
                                   keep.line.breaks=TRUE,
                                   justify="lcccc")
cat(gun.reduced)
term est.std se z pvalue
Race (x1) 0.003 0.036 0.086 0.932
Sex (x2) 0.03 0.036 0.83 0.406
Party (x3) -0.331 0.059 -5.63 0
Frame × openness (x4g) -0.101 0.163 -0.622 0.534
Frame × conscientiousness (x5g) 0.033 0.192 0.174 0.862
Frame × extraversion (x6g) 0.192 0.122 1.57 0.117
Frame × agreeableness (x7g) -0.281 0.181 -1.55 0.12
Frame × neuroticism (x8g) -0.117 0.085 -1.38 0.168
Guns frame (x9g) 0.409 0.151 2.71 0.007

Full model

gun.full <- pandoc.table.return(gun.models$model.path.coefs[[2]],
                                keep.line.breaks=TRUE,
                                justify="lcccc")
cat(gun.full)
term est.std se z pvalue
Race (x1) 0.014 0.029 0.476 0.634
Sex (x2) 0.024 0.029 0.821 0.411
Party (x3) -0.267 0.07 -3.8 0
Frame × openness (x4g) -0.12 0.16 -0.755 0.45
Frame × conscientiousness (x5g) 0 0.159 -0.003 0.998
Frame × extraversion (x6g) 0.11 0.105 1.04 0.296
Frame × agreeableness (x7g) -0.274 0.144 -1.91 0.056
Frame × neuroticism (x8g) -0.152 0.066 -2.29 0.022
Guns frame (x9g) 0.556 0.106 5.23 0
Frame × political knowledge (x10g) -0.145 0.073 -1.98 0.048
Frame × need for cognition (x11g) 0.117 0.132 0.885 0.376

Path diagram (reduced)

semPaths(gun.models$model.fit[[1]], layout="tree", rotation=2)
## Warning in lavaan(slotOptions = object@Options, slotParTable = object@ParTable, : lavaan WARNING: model has NOT
## converged!

Path diagram (full)

semPaths(gun.models$model.fit[[2]], layout="tree", rotation=2)
## Warning in lavaan(slotOptions = object@Options, slotParTable = object@ParTable, : lavaan WARNING: model has NOT
## converged!