## ----setup, include=FALSE-----------------------------------------------------
knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 8,
                      fig.height = 4.5, fig.align = "center", dpi = 120)

## ----installation, eval=FALSE-------------------------------------------------
# install.packages(c("lvmPlot", "lavaan", "shiny", "jsonlite", "svglite", "ragg"))

## ----source-install, eval=FALSE-----------------------------------------------
# install.packages(file.choose(), repos = NULL, type = "source")
# packageVersion("lvmPlot")

## ----fit-cfa------------------------------------------------------------------
library(lavaan)
library(lvmPlot)

cfa_model <- '
  visual  =~ x1 + x2 + x3
  textual =~ x4 + x5 + x6
  speed   =~ x7 + x8 + x9
'

fit <- cfa(cfa_model, data = HolzingerSwineford1939)
stopifnot(lavInspect(fit, "converged"))

## ----launch-editor, eval=FALSE------------------------------------------------
# lvmPlot(
#   fit,
#   mode = "edit",
#   label = "std",
#   stars = FALSE,
#   diagram = "all",
#   export_name = "three-factor-cfa"
# )

## ----initial-cfa, fig.cap="The three-factor CFA with standardized coefficients and factor covariances."----
plot_lvm(fit, diagram = "all", label = "std", stars = FALSE)

## ----include-variances, eval=FALSE--------------------------------------------
# lvmPlot(fit, mode = "edit", diagram = "all", residuals = TRUE,
#         label = "std", stars = FALSE)

## ----save-fit, eval=FALSE-----------------------------------------------------
# saveRDS(fit, "cfa-fit.rds")
# 
# # In a later R session:
# library(lvmPlot)
# fit <- readRDS("cfa-fit.rds")
# lvmPlot(fit, mode = "edit", label = "std", stars = FALSE,
#         diagram = "all", export_name = "three-factor-cfa")
# # In the editor, use Load state JSON.

## ----run-downloaded-code, eval=FALSE------------------------------------------
# # Run in the directory where you want the figure files to be written.
# source("three-factor-cfa-figure.R")

## ----reopen-snapshot, eval=FALSE----------------------------------------------
# lvmPlot(object, mode = "edit", layout = layout, label = label,
#         theme = theme, digits = digits, stars = stars, style = style)

## ----label-choices, eval=FALSE------------------------------------------------
# plot_lvm(fit, label = "est", digits = 3, stars = FALSE)
# plot_lvm(fit, label = "both", digits = 2, stars = FALSE)
# plot_lvm(fit, label = "none")

## ----custom-layout------------------------------------------------------------
positions <- layout_matrix(rbind(
  c("", "visual", "", "", "textual", "", "", "speed", ""),
  paste0("x", 1:9)
))

positions

## ----named-labels-------------------------------------------------------------
node_labels <- c(
  visual = "Visual ability",
  textual = "Textual ability",
  speed = "Processing speed"
)

## ----coordinate-layout, eval=FALSE--------------------------------------------
# positions <- data.frame(
#   name = c("factor", "item1", "item2", "item3"),
#   x = c(0, -2, 0, 2),
#   y = c(2, 0, 0, 0)
# )

## ----manuscript-style---------------------------------------------------------
manuscript_style <- lvm_style(
  font_family = "Times",
  node_font_size = 11,
  edge_font_size = 9,
  latent_fill = "#FFFFFF",
  observed_fill = "#FFFFFF",
  node_color = "#000000",
  node_text_color = "#000000",
  edge_color = "#000000",
  label_color = "#000000",
  label_fill = "#FFFFFF"
)

plot_lvm(
  fit, layout = positions, diagram = "measurement",
  node_labels = node_labels, label = "std", stars = FALSE,
  theme = "classic", style = manuscript_style
)

## ----manual-coefficient, eval=FALSE-------------------------------------------
# edge_positions <- data.frame(
#   from = "visual", to = "x2", type = "loading",
#   label_x = positions$x[positions$name == "visual"] + 0.45,
#   label_y = mean(positions$y)
# )
# 
# plot_lvm(fit, layout = positions, diagram = "measurement",
#          label = "std", stars = FALSE, edge_style = edge_positions)

## ----prepare-export-graph-----------------------------------------------------
figure_graph <- as_lvm_graph(fit, layout = positions)
figure_graph$nodes$label <- ifelse(
  figure_graph$nodes$name %in% names(node_labels),
  node_labels[figure_graph$nodes$name],
  figure_graph$nodes$name
)

## ----save-figures, eval=FALSE-------------------------------------------------
# save_lvm_pdf(figure_graph, "figures/cfa.pdf", width = 8, height = 4.5,
#              label = "std", stars = FALSE, theme = "classic",
#              style = manuscript_style)
# save_lvm_svg(figure_graph, "figures/cfa.svg", width = 8, height = 4.5,
#              label = "std", stars = FALSE, theme = "classic",
#              style = manuscript_style)
# save_lvm_png(figure_graph, "figures/cfa.png", width = 8, height = 4.5,
#              res = 300, label = "std", stars = FALSE, theme = "classic",
#              style = manuscript_style)

## ----bundle, eval=FALSE-------------------------------------------------------
# export_lvm_bundle(
#   figure_graph, dir = "figures/cfa-bundle", name = "cfa",
#   formats = c("pdf", "svg", "png"), label = "std", stars = FALSE,
#   style = manuscript_style, check = FALSE
# )

## ----fit-sem------------------------------------------------------------------
sem_model <- paste(cfa_model, '
  textual ~ visual
  speed ~ visual + textual
')
sem_fit <- sem(sem_model, data = HolzingerSwineford1939)

## ----structural-diagram, fig.width=7, fig.height=4, fig.cap="A structural view of the fitted example, with the measurement paths omitted."----
plot_lvm(sem_fit, diagram = "structural", label = "std", stars = FALSE,
         theme = "classic", style = manuscript_style)

## ----sem-editor, eval=FALSE---------------------------------------------------
# lvmPlot(sem_fit, mode = "edit", diagram = "all", label = "std",
#         stars = FALSE, export_name = "structural-model")

## ----parameter-table----------------------------------------------------------
params <- data.frame(
  lhs = c("engage", "engage", "engage", "achieve"),
  op = c("=~", "=~", "=~", "~"),
  rhs = c("item1", "item2", "item3", "engage"),
  est = c(1, .90, .85, .42),
  std.all = c(.78, .72, .69, .46),
  pvalue = c(NA, .001, .002, .004)
)

## ----table-editor, eval=FALSE-------------------------------------------------
# lvmPlot(params, mode = "edit", label = "std", stars = FALSE)

## ----irt-schematic, fig.width=7, fig.height=3.5-------------------------------
irt_graph <- lvm_graph(
  nodes = data.frame(
    name = c("theta", "item1", "item2", "item3"),
    label = c("Ability", "Item 1", "Item 2", "Item 3"),
    type = c("latent", rep("observed", 3)),
    role = c("trait", rep("item", 3))
  ),
  edges = data.frame(
    from = "theta", to = paste0("item", 1:3), type = "loading",
    edge_label = c("a1", "a2", "a3")
  ),
  model_type = "irt", layout_family = "irt"
)
plot_lvm(irt_graph, label = "auto", theme = "classic")

## ----multiple-groups, eval=FALSE----------------------------------------------
# fit_groups <- cfa(cfa_model, data = HolzingerSwineford1939, group = "school")
# pe <- parameterEstimates(fit_groups, standardized = TRUE)
# group_names <- lavInspect(fit_groups, "group.label")
# data.frame(group = seq_along(group_names), name = group_names)
# 
# first_group <- pe[pe$group == 1, , drop = FALSE]
# second_group <- pe[pe$group == 2, , drop = FALSE]
# 
# plot_lvm(first_group, layout = positions, diagram = "all",
#          label = "std", stars = FALSE)
# plot_lvm(second_group, layout = positions, diagram = "all",
#          label = "std", stars = FALSE)

## ----record-session, eval=FALSE-----------------------------------------------
# writeLines(capture.output(sessionInfo()), "figure-session-info.txt")

