Preface
I have ambitious goals for this book, but it is not nearly complete. I have been working on it off and on since 2012. It is accompanied by the R package psycheval (Schneider, 2023), which is also in a preliminary state of development.
Most of the figures and tables for this book were created in R or in \LaTeX. To make the content as accessible and transparent as possible, I have included buttons that will reveal the code used to make each figure or table. For example, the initial setup code used for this book can be seen by clicking the button below:
# Load packages
library(extrafont)
loadfonts("win", quiet = TRUE)
library(tufte)
library(knitr)
library(sn)
library(fMultivar)
library(IDPmisc)
library(psych)
library(tidyverse)
library(gganimate)
library(ggforce)
library(sjmisc)
library(WJSmisc)
library(tippy)
library(tikzDevice)
library(patchwork)
library(qualvar)
library(modeest)
library(tinter)
library(ggfx)
library(ggtext)
library(lemon)
library(signs)
library(scales)
library(psycheval)
library(bezier)
library(DescTools)
# Set options
options(knitr.kable.digits = 2, knitr.kable.na = '')
::opts_template$set(marginfigure = list(fig.column = "margin", fig.cap.location = "top", out.width = "100%", fig.align = "left"),
knitrbodyfigure = list(fig.column = "body", fig.cap.location = "margin"))
# Default fonts and colors
= "Equity Text A Tab"
bfont = 16
bsize <- c("royalblue4", "firebrick4", "#51315E")
myfills
# Function for converting base size to geom_text size
<- function(base_size, ratio = 0.8) {
ggtext_size * base_size / ggplot2:::.pt
ratio
}
= ggtext_size(bsize)
btxt_size
# Default geoms and themes
::update_geom_defaults("text",
ggplot2list(family = bfont, size = btxt_size))
::update_geom_defaults("label",
ggplot2list(
family = bfont,
size = btxt_size,
label.padding = unit(0, "lines"),
label.size = 0
))
::update_geom_defaults("richtext",
ggplot2list(family = bfont, size = btxt_size))
::update_geom_defaults("density", list(fill = myfills[1]))
ggplot2<- function(...) {
geom_text_fill geom_label(...,
label.padding = unit(0, "lines"),
label.size = 0)
}theme_set(theme_minimal(base_size = bsize, base_family = bfont))
# font family
<- function(x, style = "font-family:serif") {
span_style paste0('<span style=\"',
style,'\">',
x,"</span>")
}
# Probability labels
<- function(p,
prob_label accuracy = 0.01,
digits = NULL,
max_digits = NULL,
remove_leading_zero = TRUE,
round_zero_one = TRUE) {
if (is.null(digits)) {
<- scales::number(p, accuracy = accuracy)
l else {
} <- abs(ceiling(log10(p + p / 1000000000)) - digits)
sig_digits > 0.99] <- abs(ceiling(log10(1 - p[p > 0.99])) - digits + 1)
sig_digits[p ceiling(log10(p)) == log10(p)) & (-log10(p) >= digits)] <- sig_digits[ceiling(log10(p)) == log10(p)] - 1
sig_digits[(is.infinite(sig_digits)] <- 0
sig_digits[<- purrr::map2_chr(p,
l
sig_digits,
formatC,format = "f",
flag = "#")
}if (remove_leading_zero) l <- sub("^-0","-", sub("^0","", l))
if (round_zero_one) {
== 0] <- "0"
l[p == 1] <- "1"
l[p == -1] <- "-1"
l[p
}
if (!is.null(max_digits)) {
if (round_zero_one) {
round(p, digits = max_digits) == 0] <- "0"
l[round(p, digits = max_digits) == 1] <- "1"
l[round(p, digits = max_digits) == -1] <- "-1"
l[else {
} round(p, digits = max_digits) == 0] <- paste0(".", paste0(rep("0", max_digits), collapse = ""))
l[round(p, digits = max_digits) == 1] <- paste0("1.", paste0(rep("0", max_digits), collapse = ""))
l[round(p, digits = max_digits) == -1] <- paste0("-1.", paste0(rep("0", max_digits), collapse = ""))
l[
}
}
dim(l) <- dim(p)
l
}
# Set table column width
# https://github.com/rstudio/bookdown/issues/122#issuecomment-221101375
<- function(kable_output, width, tag = "</caption>"){
html_table_width <- paste0(
width_html paste0('<col width="',
width,'">'),
collapse = "\n")
sub(tag,
paste0(tag,
"\n",
width_html),
kable_output)
}
# Make a matrix with braces
<- function(M, brace = "bmatrix", includenames=TRUE) {
bmatrix if (includenames) {
<- cbind(rownames(M),M)
M <- rbind(colnames(M), M)
M
}<- paste(apply(M,
M MARGIN = 1,
FUN = paste0,
collapse = " & "),
collapse = "\\\\\n")
if (!is.null(brace)) {
<- paste0("\\begin{",brace,"}\n", M, "\n\\end{", brace , "}")
M
}
M
}
# defword <- function(word,
# note,
# wordclass="defword",
# noteclass = "aside defword",
# icon = "⊕") {
# # Adapted from tufte:::marginnote_html
#
# sprintf(
# paste0(
# "<span class=\"%s\">%s</span>",
# "<span class=\"%s\">",
# "<label for=\"tufte-mn-\" class=\"margin-toggle\">%s</label>",
# "<input type=\"checkbox\" id=\"tufte-mn-\" class=\"margin-toggle\">%s",
# "</span>"
# ),
# wordclass,
# word,
# noteclass,
# icon,
# note
# )
# }
# Hooks -------
# Enclose collapsible r chunk in button
::opts_hooks$set(button_r = function(options) {
knitrif (isTRUE(options$button_r)) {
$button_before_r <- TRUE
options$button_after <- TRUE
options$echo = TRUE; options$eval = FALSE
options
}
options
})
# Enclose collapsible latex chunk in button
::opts_hooks$set(button_latex = function(options) {
knitrif (isTRUE(options$button_latex)) {
$button_before_latex <- TRUE
options$button_after <- TRUE
options$echo = TRUE; options$eval = FALSE
options
}
options
})
# before button for collapsible r chunk
$set(
knit_hooksbutton_before_r = function(before, options, envir) {
if (before) {
<- "R Code"
codetype if (!is.null(options$figlabel)) {
<- paste0(codetype, " for @", options$figlabel)
codetype
} return(
paste0(
'<div class="wrap-collapsible" style="margin-top: 1em">',
"\n",
'<input id="collapsible-',
$label,
options'" class="toggle" type="checkbox">',
"\n",
'<label for="collapsible-',
$label,
options'" class="lbl-toggle">', codetype,'</label>',
'<div class="collapsible-content">',
"\n",
'<div class="content-inner">'
)
)
}
}
)
# before button for collapsible latex chunk
$set(
knit_hooksbutton_before_latex = function(before, options, envir) {
if (before) {
<- "$\\rm\\LaTeX~Code$"
codetype if (!is.null(options$figlabel)) {
<- paste0(codetype, " for @", options$figlabel)
codetype
} return(
paste0(
'<div class="wrap-collapsible" style="margin-top: 1em">',
"\n",
'<input id="collapsible-',
$label,
options'" class="toggle" type="checkbox">',
"\n",
'<label for="collapsible-',
$label,
options'" class="lbl-toggle">',
codetype,'</label>',
'<div class="collapsible-content">',
"\n",
'<div class="content-inner">'
)
)
}
}
)
# After button for collapsible chunks
$set(button_after = function(before, options, envir) {
knit_hooksif (!before) return('</div></div></div>')
})
In addition, all the files and code used to create this book can be found in its Github repository.
To avoid repeated citation, I must note that in preparing this book, I have drawn heavily—and no doubt unconsciously—from many authoritative sources on psychometrics, statistical analysis, and linear algebra (Cohen et al., 2003; Crocker & Algina, 2006; Eaton, 2007; Furr, 2017; Nunnally, 1967; Raykov & Marcoulides, 2011; Strang, 2016). I am also grateful to the many unsung authors at Wikipedia and Mathematica who maintain wonderfully comprehensive, up-to-date, and well-referenced documentation of all things mathematical and statistical.