-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathplot_fds.R
161 lines (151 loc) · 6.37 KB
/
plot_fds.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#'@title Fraction of Design Space Plot
#'
#'@description Creates a fraction of design space plot
#'
#'@param genoutput The design, or the output of the power evaluation functions. This can also be a list
#'of several designs, which will result in all of them being plotted in a row (for easy comparison).
#'@param model Default `NULL`. The model, if `NULL` it defaults to the model used in `eval_design` or `gen_design`.
#'@param continuouslength Default `11`. The precision of the continuous variables. Decrease for faster (but less precise) plotting.
#'@param plot Default `TRUE`. Whether to plot the FDS, or just calculate the cumulative distribution function.
#'@param sample_size Default `10000`. Number of samples to take of the design space.
#'@param yaxis_max Default `NULL`. Manually set the maximum value of the prediction variance.
#'@param description Default `Fraction of Design Space`. The description to add to the plot. If a vector and multiple designs
#'passed to genoutput, it will be the description for each plot.
#'@return Plots design diagnostics, and invisibly returns the vector of values representing the fraction of design space plot. If multiple
#'designs are passed, this will return a list of all FDS vectors.
#'@import graphics grDevices
#'@export
#'@examples
#'#We can pass either the output of gen_design or eval_design to plot_correlations
#'#in order to obtain the correlation map. Passing the output of eval_design is useful
#'#if you want to plot the correlation map from an externally generated design.
#'
#'#First generate the design:
#'
#'candidatelist = expand.grid(X1 = c(1, -1), X2 = c(1, -1))
#'
#'design = gen_design(candidatelist, ~(X1 + X2), 15)
#'
#'plot_fds(design)
plot_fds = function(genoutput, model = NULL, continuouslength = 1001, plot=TRUE,
sample_size = 10000,
yaxis_max = NULL, description="Fraction of Design Space") {
if(inherits(genoutput,"list") && length(genoutput) > 1) {
old.par = par(no.readonly = TRUE)
on.exit(par(old.par), add = TRUE)
par(mfrow = c(1,length(genoutput)))
fds_values = list()
if(!plot && !is.null(yaxis_max)) {
warning("`plot = FALSE` but `yaxis_max` non-NULL. Setting `yaxis_max` to NULL")
yaxis_max = NULL
}
if(is.null(yaxis_max)) {
for(i in 1:length(genoutput)) {
fds_values[[i]] = plot_fds(genoutput[[i]], model=model,
continuouslength = continuouslength, plot=FALSE)
}
yaxis_max = max(unlist(fds_values)) + max(unlist(fds_values)) / 20
}
if(length(description) == 1) {
description = rep(description, length(genoutput))
}
if(plot) {
for(i in 1:length(genoutput)) {
fds_values[[i]] = plot_fds(genoutput[[i]], model=model, continuouslength = continuouslength,
plot=plot, yaxis_max=yaxis_max,
description = description[i])
}
}
return(invisible(fds_values))
}
#Remove skpr-generated REML blocking indicators if present
if (!is.null(attr(genoutput, "splitanalyzable"))) {
if (attr(genoutput, "splitanalyzable")) {
allattr = attributes(genoutput)
remove_cols = which(colnames(genoutput) %in% allattr$splitcolumns)
if(length(remove_cols) > 0) {
genoutput = genoutput[, -remove_cols, drop = FALSE]
allattr$names = allattr$names[-remove_cols]
}
attributes(genoutput) = allattr
}
}
if (!is.null(attr(genoutput, "splitcolumns"))) {
allattr = attributes(genoutput)
genoutput = genoutput[, !(colnames(genoutput) %in% attr(genoutput, "splitcolumns")), drop = FALSE]
allattr$names = allattr$names[!allattr$names %in% attr(genoutput, "splitcolumns")]
attributes(genoutput) = allattr
}
Iopt = attr(genoutput, "I")
V = attr(genoutput, "variance.matrix")
if(is.null(model)) {
if(!is.null(attr(genoutput, "generating.model"))) {
model = attr(genoutput, "generating.model")
} else {
model = ~.
}
}
if (!is.null(attr(genoutput, "runmatrix"))) {
genoutput = attr(genoutput, "runmatrix")
}
factornames = colnames(genoutput)[unlist(lapply(genoutput, class)) %in% c("factor", "character")]
if (length(factornames) > 0) {
contrastlist = list()
for (name in 1:length(factornames)) {
contrastlist[[factornames[name]]] = "contr.sum"
}
} else {
contrastlist = NULL
}
sample_list = list()
for (col in 1:ncol(genoutput)) {
if (inherits(genoutput[, col], c("factor", "character"))) {
vals = unique(genoutput[, col])
}
if (is.numeric(genoutput[, col])) {
vals = seq(-1, 1, length.out = continuouslength)
}
sample_list[[colnames(genoutput)[col]]] = vals[sample(seq_len(length(vals)), size=sample_size, replace = TRUE)]
}
samples = as.data.frame(sample_list)
#------Normalize/Center numeric columns ------#
for (column in 1:ncol(genoutput)) {
if (is.numeric(genoutput[, column])) {
midvalue = mean(c(max(genoutput[, column]), min(genoutput[, column])))
genoutput[, column] = (genoutput[, column] - midvalue) / (max(genoutput[, column]) - midvalue)
}
}
mm = model.matrix(model, genoutput, contrasts.arg = contrastlist)
samplemm = model.matrix(model, samples, contrasts.arg = contrastlist)
testcor = solve(t(mm) %*% solve(V) %*% mm)
v = list()
for (i in 1:nrow(samplemm)) {
xi = samplemm[i, ]
v[[i]] = t(xi) %*% testcor %*% xi
}
vars = do.call(rbind, v)
varsordered = vars[order(vars)]
meanindex = which(abs(mean(varsordered) - varsordered) == min(abs(mean(varsordered) - varsordered)))
scale = varsordered[meanindex]
if (length(scale) > 1) {
scale = scale[1]
}
varsorderedscaled = varsordered / scale * Iopt
midval = varsorderedscaled[sample_size/2]
if(is.null(yaxis_max)) {
maxyaxis = max(varsorderedscaled) + max(varsorderedscaled) / 20
} else {
maxyaxis = yaxis_max
}
if(plot) {
plot(1:length(varsorderedscaled) / length(varsorderedscaled), varsorderedscaled, ylim = c(0, maxyaxis), type = "n",
xlab = description, ylab = "Prediction Variance",
xlim = c(0, 1), xaxs = "i", yaxs = "i")
abline(v = 0.5, untf = FALSE, lty = 2, col = "red", lwd = 2)
abline(h = midval, untf = FALSE, lty = 2, col = "red", lwd = 2)
lines(1:length(varsorderedscaled) / length(varsorderedscaled), varsorderedscaled, lwd = 2, col = "blue")
invisible(varsorderedscaled)
} else {
return(varsorderedscaled)
}
}