Nothing
## convenience function for rainbow in HCL space
hclrainbow <- function(n) hcl(h = seq(0, 360 * (n - 1) / n, length = n), c = 80, l = 60)
## region plot graphic function
regionplot <- function (object, parg = list(type = NULL, ref = NULL, alias = TRUE),
names = TRUE, main = NULL, xlab = "", ylab = "Latent trait", ylim = NULL,
off = 0.1, col = NULL, linecol = 2, srt = 45, adj = c(1.1, 1.1), axes = TRUE, ...)
{
## process parg list
type <- parg$type
ref <- parg$ref
alias <- if (is.null(parg$alias)) TRUE else parg$alias
## fetch requested threshold parameters
tp <- threshpar(object, type = type, ref = ref, alias = alias, vcov = FALSE)
## process argument 'col'
oj <- sapply(tp, function (j) sum(!is.na(j)))
if (is.null(col)) {
cols <- lapply(oj, function (j) gray.colors((j + 1)))
} else if (is.character(col)) {
stopifnot(length(col) == (max(oj) + 1))
cols <- lapply(oj, function (j) col[1:(j + 1)])
} else if (is.list(col)) {
stopifnot(length(col) == length(oj))
oj2 <- lapply(col, function (j) length(j))
stopifnot(all(oj2 >= oj + 1))
cols <- col
} else if (is.function(col)) {
cols <- lapply(oj, function (j) col(j + 1))
} else stop("Argument 'col' is misspecified (see ?regionplot for possible values).")
## setup par, number of items, axis labels
## opar <- par(mar = c(4.25, 4.25, if (is.null(main)) 1 else 3, 2.5))
m <- length(tp)
if (isTRUE(names)) {
nms <- names(tp)
if(is.null(nms)) nms <- paste0("Item", formatC(1:m, width = nchar(m), digits = 0, flag = "0"))
}
if (is.character(names)) {
stopifnot(length(names) == m)
nms <- names
names <- TRUE
}
if(!names) {
lab <- rep(NA, m)
lab[c(1, m)] <- c(1, m)
pr <- pretty(1:m)
pr <- pr[pr > 1 & pr < m]
lab[pr] <- pr
nms <- lab
}
## check if all threshold parameters are in order, if not, calculate sorted ones
us <- sapply(tp, is.unsorted)
if (any(us)) {
usj <- which(us)
for (j in usj) {
tpj <- tp[[j]]
nj <- length(tpj)
## check if there is a point with a biggest parameter, if yes, take mean
for (i in 1:nj) {
if (all(tpj[i] > tpj[(i + 1):nj])) {
tpj[i] <- mean(tpj[i:nj])
tpj <- tpj[-(i + 1:nj)]
break
}
}
## recursive sorting if there is still unorder (e.g. 4, 2, 3, 1)
while(is.unsorted(tpj)) {
uo_pos <- which(diff(tpj) < 0) # locate unordered parameters, returns position of the first
tpj[uo_pos] <- (tpj[uo_pos] + tpj[uo_pos + 1]) / 2 # replace first with location of intersection of ccc curves (= (eps1 + eps2)/ 2)
tpj <- tpj[-(uo_pos + 1)] # remove second
}
tp[[j]] <- tpj
}
}
## setup axis range and positions
if (is.null(ylim)) ylim <- extendrange(unlist(tp, use.names = FALSE), f = 0.25)
xi <- 0:m + c(0:(m - 1), m - 1) * off
xlim <- c(xi[1], xi[m + 1])
## setup graphical window
plot(0, 0, xlim = xlim, ylim = ylim, type = "n", xaxs = "i", yaxs = "i", axes = FALSE, ylab = ylab, xlab = xlab, main = main, ...)
## plot items
for (j in seq_along(tp)) {
rect(xleft = xi[j], xright = xi[j] + 1, ybottom = c(ylim[1], tp[[j]]), ytop = c(tp[[j]], ylim[2]), col = cols[[j]])
}
## indicate unordered parameters
if ((is.null(type) || type == "mode")) {
orgtp <- threshpar(object, type = type, ref = ref, alias = alias, vcov = FALSE)
uo_items <- which(!sapply(mapply(all.equal, tp, orgtp, check.attributes = FALSE, SIMPLIFY = FALSE, USE.NAMES = FALSE), is.logical))
for (j in uo_items) {
uo_pars <- setdiff(orgtp[[j]], tp[[j]])
lines(x = rep(c(xi[j], xi[j] + 1, NA), length(uo_pars)), y = rep(uo_pars, each = 3), col = linecol, lty = 2)
}
}
## add axes
if(axes) {
axis(2)
axis(4)
if(names) {
text(xi[-(m + 1)] + 0.5, par("usr")[3], labels = nms, srt = srt, adj = adj, xpd = TRUE, cex = 0.9)
} else {
axis(1, at = (xi[-(m + 1)] + 0.5), labels = nms)
}
}
box()
## on.exit(par(opar))
}
## profiles of item, threshold or discrimination parameters
profileplot <- function(object,
what = c("items", "thresholds", "discriminations", "guessings", "uppers"),
parg = list(type = NULL, ref = NULL, alias = TRUE, logit = FALSE), index = TRUE,
names = TRUE, main = NULL, abbreviate = FALSE, ref = TRUE, col = "lightgray",
border = "black", pch = NULL, cex = 1, refcol = "lightgray",
linecol = "black", lty = 2, ylim = NULL, xlab = NULL, ylab = NULL,
add = FALSE, srt = 45, adj = c(1.1, 1.1), axes = TRUE, ...)
{
## check input
what <- match.arg(what)
if(what == "thresholds") type <- parg$type
refpar <- parg$ref
alias <- if(is.null(parg$alias)) TRUE else parg$alias
logit <- parg$logit
addargs <- list(...)
if("difficulty" %in% names(addargs)) {
warning("The argument 'difficulty' is deprecated and not longer used. All plotted parameters are difficulty parameters.")
}
if("center" %in% names(addargs)) {
warning("The argument 'center' is deprecated and not longer used. Centered parameters can be plotted when setting the 'ref' argument of 'parg' to NULL (default).")
}
## parameters to be plotted
if(what == "items") {
cf <- itempar(object, ref = refpar, alias = alias, vcov = FALSE)
ncf <- length(cf)
lb <- "difficulty"
} else if(what == "thresholds") {
cf <- coef(threshpar(object, ref = refpar, alias = alias, type = type,
vcov = FALSE), type = "matrix")
ncf <- nrow(cf)
ncat <- ncol(cf)
lb <- "threshold"
} else if(what == "discriminations") {
cf <- discrpar(object, ref = refpar, alias = alias, vcov = FALSE)
ncf <- length(cf)
lb <- "discrimination"
} else if(what == "guessings") {
cf <- guesspar(object, alias = alias, vcov = FALSE, logit = logit)
ncf <- length(cf)
lb <- "guessing"
} else {
cf <- upperpar(object, alias = alias, vcov = FALSE, logit = logit)
ncf <- length(cf)
lb <- "upper asymptote"
}
cf_ref <- mean(cf)
## labeling
if(is.null(names)) names <- !index
if(isTRUE(names)) nms <- if(what == "thresholds") rownames(cf) else names(cf)
if(is.character(names)) {
nms <- names
names <- TRUE
}
if(!names & index) {
lab <- rep(NA, ncf)
lab[c(1, ncf)] <- c(1, ncf)
pr <- pretty(1:ncf)
pr <- pr[pr > 1 & pr < ncf]
lab[pr] <- pr
nms <- lab
}
## abbreviation
if(is.logical(abbreviate)) {
nlab <- max(nchar(nms))
abbreviate <- if(abbreviate) {
as.numeric(cut(nlab, c(-Inf, 1.5, 4.5, 7.5, Inf)))
} else {
nlab
}
}
nms <- abbreviate(nms, abbreviate)
## graphical parameter processing
type <- if(index) "b" else "p"
missing_col_border <- !missing(col) && missing(border)
if(what != "thresholds") {
if(is.null(pch)) pch <- 21
pch <- rep(pch, length.out = ncf)
col <- rep(col, length.out = ncf)
border <- rep(border, length.out = ncf)
} else {
col <- matrix(rep(t(col), length.out = ncf * ncat), ncol = ncat,
byrow = TRUE)
border <- matrix(rep(t(border), length.out = ncf * ncat), ncol = ncat,
byrow = TRUE)
linecol <- rep(linecol, length.out = ncat)
if(!is.null(pch)) pch <- matrix(rep(t(pch), length.out = ncf * ncat),
ncol = ncat, byrow = TRUE)
}
if((!index | is.null(pch)) && missing_col_border) border <- col
cex <- rep(cex, length.out = ncf)
if(is.null(ylim)) ylim <- range(cf, na.rm = TRUE)
ylim <- rep(ylim, length.out = 2)
xlim <- if(!index && what == "thresholds" && ncat > 1) {
extendrange(c(1, ncat), f = 0.25)
} else {
NULL
}
if(is.null(xlab)) xlab <- if(index) {
""
} else {
if(what != "thresholds") "Items" else "Categories"
}
if(is.null(ylab)) ylab <- paste("Item", lb, "parameters")
## raw plot
ix <- if(index) {
1:ncf
} else if(what == "thresholds") {
matrix(rep(1:ncat, each = ncf), nrow = ncf)
} else {
rep(0, ncf)
}
if(!add) {
plot(ix, rep(0, length(ix)), xlab = xlab, ylab = ylab, type = "n",
axes = FALSE, ylim = ylim, xlim = xlim, main = main, ...)
if(ref & what != "thresholds") abline(h = cf_ref, col = refcol)
if(axes) axis(2)
if(!index & what == "thresholds" & axes) {
axis(1, at = unique(ix), labels = paste("Category", 1:ncat))
}
box()
}
## actual data
if(!index & names) {
if(what == "thresholds") {
for(i in 1:ncat) text(nms, x = ix[, i], y = cf[, i], col = border[, i])
} else {
text(nms, x = ix, y = cf, col = border)
}
} else {
if(what == "thresholds") {
for(i in 1:ncat) {
lines(ix, cf[, i], type = type, lty = lty, pch = NA, col = linecol[i],
cex = cex)
if(is.null(pch)) {
text(x = ix, y = cf[, i], labels = paste0("C", i), col = border[, i],
cex = cex * 0.8, font = 2)
} else {
lines(x = ix, y = cf[, i], type = type, lty = 0, pch = pch[, i],
col = border[, i], bg = col[, i], cex = cex)
}
}
} else {
lines(ix, cf, type = type, lty = lty, pch = NA, col = linecol, cex = cex)
lines(ix, cf, type = type, lty = 0, pch = pch, col = border, bg = col,
cex = cex)
}
if(index && !add && axes) {
if(names) {
text(ix, par("usr")[3], labels = nms, srt = srt, adj = adj, xpd = TRUE,
cex = 0.9)
} else {
axis(1, at = ix, labels = nms)
}
}
}
}
## ICC/CCC/response curve functions plot
curveplot <- function(object, ref = NULL, items = NULL, names = NULL,
layout = NULL, xlim = NULL, ylim = c(0, 1), col = NULL, lty = NULL,
main = NULL, xlab = "Latent trait", ylab = "Probability", add = FALSE, ...)
{
## setup relevant informations and process input
tp <- coef(threshpar(object, type = "mode", vcov = FALSE), type = "matrix")
oj <- apply(tp, 1, function (j) sum(!is.na(j)) + 1)
m0 <- nrow(tp)
idx <- rep(1:m0, oj)
nms <- if (!is.null(colnames(object$data))) colnames(object$data) else paste0("Item", formatC(1:m0, width = nchar(m0), digits = 0, flag = "0"))
if (is.null(items)) {
items <- 1:m0
} else if (is.numeric(items)) {
stopifnot(all(items %in% 1:m0))
} else if (is.character(items)) {
stopifnot(all(items %in% nms))
items <- which(nms %in% items)
}
m <- length(items)
## setup plotting parameters
if (is.null(names)) {
pnms <- nms
} else {
stopifnot(length(names) == m)
pnms <- rep(NULL, m0)
pnms[items] <- names
}
if (is.null(layout)) {
nrow <- ceiling(sqrt(m))
ncol <- ceiling(m / nrow)
layout <- matrix(1:(nrow * ncol), nrow = nrow, ncol = ncol)
} else stopifnot(prod(dim(layout)) >= m)
if (is.null(xlim)) xlim <- extendrange(unclass(tp), f = 0.25)
if (is.null(col)) col <- hclrainbow(max(oj))
if (is.null(lty)) lty <- 1 else stopifnot(length(lty) %in% c(1, max(oj)))
## get probabilities
theta <- seq(from = xlim[1], to = xlim[2], by = 0.1)
pr <- predict(object, newdata = theta, type = "probability", ref = ref)
## setup plotting area, setup par
if (!add) {
layout(layout)
opar <- par(mar = c(4.25, 4.25, 3, 2.5))
} else {
if (m > 1) stop("Overlaying response curves is only possible with a single item plotted.")
}
## loop through items and plot CCC
for (j in items) matplot(x = theta, y = pr[, j == idx], type = "l", main = if (is.null(main)) pnms[j] else main, xaxs = "i",
lty = lty, col = col, xlab = xlab, ylab = ylab, ylim = ylim, xlim = xlim, add = add, ...)
if (!add) {
layout(matrix(1, nrow = 1, ncol = 1))
on.exit(par(opar))
}
}
## person item plot
piplot <- function(object, pcol = NULL, histogram = TRUE, ref = NULL,
items = NULL, xlim = NULL, names = NULL, labels = TRUE,
main = "Person-Item Plot", xlab = "Latent trait", abbreviate = FALSE,
cex.axis = 0.8, cex.text = 0.5, cex.points = 1.5,
grid = TRUE, ...)
{
## FIXME: general way to handle prettifying options, e.g. supply all colors as a list?
## handle grid
if(is.null(grid)) grid <- TRUE
if(is.logical(grid)) grid <- if(grid) "lightgray" else "transparent"
## setup parameters, number of items and item labels
tp <- threshpar(object, ref = ref, vcov = FALSE)
ip <- sapply(tp, mean)
m <- length(ip)
nms <- names(ip)
pp <- personpar(object, ref = ref, vcov = FALSE)
type <- attributes(pp)$type
## distinguish based on "type", preprocessing
if(type == "normal") {
gp <- split(pp, rep(1:(length(pp) / 2), each = 2))
if(!is.null(pcol)) {
pcol <- rep_len(pcol, length.out = length(gp))
coltrans <- apply(col2rgb(pcol), 2, function(x) {
tmp <- split(x, 1:3)
rgb(tmp[[1]], tmp[[2]], tmp[[3]], 25, maxColorValue = 255)
})
} else if(length(gp) > 1) {
pcol <- hclrainbow(length(gp))
coltrans <- apply(col2rgb(pcol), 2, function(x) {
tmp <- split(x, 1:3)
rgb(tmp[[1]], tmp[[2]], tmp[[3]], 25, maxColorValue = 255)
})
} else {
pcol <- "gray50"
tmp <- col2rgb(pcol)
coltrans <- rgb(tmp[1, 1], tmp[2, 1], tmp[3, 1], 25, maxColorValue = 255)
}
pp <-
if(!is.null(object$impact)) {
split(personpar(object, personwise = TRUE), object$impact)
} else {
list(personpar(object, personwise = TRUE))
}
} else if(type == "discrete") {
if(!is.null(pcol)) {
if(length(pcol) != 1) {
pcol <- pcol[1]
}
} else {
pcol <- "gray50"
}
ppr <- range(as.numeric(names(pp)))
rs <- rowSums(object$data, na.rm = TRUE)
rs <- rs[rs >= ppr[1] & rs <= ppr[2]]
ppt <- table(pp[rs])
pptx <- as.numeric(names(ppt))
}
## process argument items
if(is.null(items)) {
items <- 1:m
} else if(is.numeric(items)) {
stopifnot(all(items %in% 1:m))
} else if(is.character(items)) {
stopifnot(all(items %in% nms))
items <- which(items %in% nms)
} else {
stop("Argument 'items' is misspecified (see ?piplot for possible values).")
}
## subset to requested items
m <- length(items)
ip <- ip[items]
tp <- tp[items]
nms <- nms[items]
## abbreviation
if(is.logical(abbreviate)) {
nlab <- max(nchar(nms))
abbreviate <-
if(abbreviate) {
as.numeric(cut(nlab, c(-Inf, 1.5, 4.5, 7.5, Inf)))
} else {
nlab
}
}
nms <- abbreviate(nms, abbreviate)
w <- max(nchar(nms)) * 0.5
## setup x axis limits, backup par
xlim <-
if(is.null(xlim)) {
if(type == "normal") {
range(c(unlist(tp), unlist(lapply(pp, function(x) hist(x, plot = FALSE)$breaks))))
} else if(type == "discrete") {
range(c(unlist(tp), pp))
}
} else {
xlim
}
ylim <- c(1, m)
## setup graphic region
layout(matrix(1:2, ncol = 1, nrow = 2), heights = c(1, 2))
## person parameter plot different for CML vs. MML
opar <- par(mar = c(0, w, 2.5, 1))
if(type == "normal") {
ylimpp1 <- max(unlist(lapply(pp, function(x) {
hist(x, plot = FALSE)$density
})))
ylimpp2 <- max(sapply(gp, function(x) dnorm(x[1], x[1], sqrt(x[2]))))
ylimpp <- c(0, max(ylimpp1, ylimpp2))
## FIXME: allow "border" color to be defined by the user
if(histogram) {
hist(pp[[1]], freq = FALSE, xlim = xlim, ylim = ylimpp,
col = coltrans[1], border = "gray", axes = FALSE, xlab = "",
ylab = "", main = main)
x <- NULL ## for R CMD check due to the following expression in curve()
curve(dnorm(x, gp[[1]][1], sqrt(gp[[1]][2])), xlim[1], xlim[2],
col = pcol[1], add = TRUE)
if(length(gp) > 1) {
for(a in 2:length(gp)) {
hist(pp[[a]], freq = FALSE, xlim = xlim, ylim = ylimpp,
col = coltrans[a], border = "gray", add = TRUE)
curve(dnorm(x, gp[[a]][1], sqrt(gp[[a]][2])), xlim[1], xlim[2],
col = pcol[a], add = TRUE)
}
legend("topleft", legend = levels(object$impact), col = pcol, lty = 1,
bty = "n", title = "Impact", cex = 0.5)
}
} else {
curve(dnorm(x, gp[[1]][1], sqrt(gp[[1]][2])), xlim[1], xlim[2],
ylim = ylimpp, col = pcol[1], axes = FALSE, xlab = "", ylab = "",
main = main)
if(length(gp) > 1) {
for(a in 2:length(gp)) {
curve(dnorm(x, gp[[a]][1], sqrt(gp[[a]][2])), xlim[1], xlim[2],
col = pcol[a], add = TRUE)
}
legend("topleft", legend = levels(object$impact), col = pcol, lty = 1,
bty = "n", title = "Impact", cex = 0.5)
}
}
} else if(type == "discrete") {
plot(x = 0, xlim = xlim, ylim = c(0, max(ppt)), type = "n", axes = FALSE,
xlab = "", ylab = "", main = main, cex.axis = cex.axis, ...)
points(x = pptx, y = ppt, type = "h", col = pcol, lend = 2, lwd = 5, ...)
}
box()
## item/threshold parameter plot
par(mar = c(4.5, w, 0, 1))
plot(x = 0, xlim = xlim, ylim = ylim, type = "n", axes = FALSE, xlab = xlab,
ylab = "", cex.axis = cex.axis)
## grid (horizontal gray lines for the items or none)
if(grid != "transparent") {
abline(h = 1:m, col = grid)
}
for(i in 1:m) {
lines(y = rep(i, length(tp[[i]])), x = tp[[i]], type = "b", pch = 1,
cex = cex.points, ...)
if(labels) {
text(x = tp[[i]], y = rep(i, length(tp[[i]])),
labels = gsub("C", "", names(tp[[i]])), cex = cex.text, ...)
}
}
points(x = ip, y = 1:m, pch = 16, cex = cex.points, ...)
axis(side = 1, cex.axis = cex.axis)
axis(side = 2, at = 1:m, labels = nms, las = 2, cex.axis = cex.axis)
box()
## restore par
layout(matrix(1, nrow = 1, ncol = 1))
on.exit(par(opar))
}
## information curve plot
infoplot <- function(object, what = c("categories", "items", "test"),
ref = NULL, items = NULL, names = NULL, layout = NULL, xlim = NULL,
ylim = NULL, col = NULL, lty = NULL, lwd = NULL, main = NULL, legend = TRUE,
xlab = "Latent trait", ylab = "Information", add = FALSE, ...)
{
## process input
what <- match.arg(what)
## setup items
nms <- if (!is.null(colnames(object$data))) colnames(object$data) else paste0("Item", formatC(1:ncol(object$data), width = nchar(ncol(object$data)), digits = 0, flag = "0"))
m <- length(nms)
if (is.null(items)) {
items <- 1:m
} else if (is.numeric(items)) {
stopifnot(all(items %in% 1:m))
} else if (is.character(items)) {
stopifnot(all(items %in% nms))
items <- which(nms %in% items)
}
m <- length(items)
## setup plotting names
if (is.null(names)) {
pnms <- nms
} else {
stopifnot(length(names) == m)
pnms <- rep(NULL, m)
pnms[items] <- names
}
## setup layout
if (what == "test") {
if (!is.null(layout)) warning("Argument 'layout' is not considered when visualizing test information.")
layout <- matrix(1, nrow = 1, ncol = 1)
overlay <- TRUE
} else if (is.null(layout)) {
if (what == "items") {
layout <- matrix(1, nrow = 1, ncol = 1)
overlay <- TRUE
} else {
nrow <- ceiling(sqrt(m))
ncol <- ceiling(m / nrow)
layout <- matrix(1:(nrow * ncol), nrow = nrow, ncol = ncol)
overlay <- FALSE
}
} else {
stopifnot(prod(dim(layout)) >= m)
overlay <- FALSE
}
## setup graphical stuff and information
tp <- coef(threshpar(object, type = "mode", vcov = FALSE), type = "matrix")
if (is.null(xlim)) xlim <- extendrange(unclass(tp), f = 0.5)
theta <- seq(from = xlim[1], to = xlim[2], by = 0.05)
if (is.null(lty)) lty <- 1
if (what == "test") {
type <- "test-information"
if (is.null(col)) col <- "black"
if (is.null(main)) main <- "Test Information"
} else if (what == "items") {
type <- "item-information"
if (is.null(col)) col <- if (overlay) hclrainbow(m) else "black"
if (is.null(main) & overlay) main <- "Item Information"
} else {
type <- "category-information"
if (is.null(col)) col <- hclrainbow(ncol(tp) + 1)
}
info <- predict(object, ref = ref, type = type, newdata = theta)
## plot requested information
if (!add) {
layout(layout)
opar <- par(mar = c(4.25, 4.25, 3, 2.5))
} else {
if (!overlay && m > 1 && what != "test") stop("Overlaying information curves is only possible for tests or single items.")
}
if (overlay) {
if (what == "items") info <- info[, items]
matplot(x = theta, y = info, xlim = xlim, ylim = ylim, type = "l", main = main, lty = lty, col = col, lwd = lwd,
xlab = xlab, ylab = ylab, xaxs = "i", add = add, ...)
if (what == "items" && !add && legend) legend(x = "topleft", legend = pnms[items], col = col, lwd = lwd, lty = lty, bty = "n")
} else {
for (j in items) {
matplot(x = theta, y = info[, grepl(paste0(nms[j], "-"), colnames(info))], xlim = xlim, ylim = ylim, xaxs = "i",
main = pnms[j], type = "l", lty = lty, lwd = lwd, col = col, xlab = xlab, ylab = ylab, add = add, ...)
}
}
if (!add) {
layout(matrix(1, nrow = 1, ncol = 1))
on.exit(par(opar))
}
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.