#' @title Function for plotting optimization paths.
#'
#' @description
#' Same as [plotOptPath()], but renders the plots for just 1 iteration
#' and returns a list of plots instead of printing the plot. Useful, if you want
#' to extract single plots or to edit the ggplots by yourself.
#'
#' @param op [OptPath]\cr
#' Optimization path.
#' @param iter (`integer(1)`)\cr
#' Selected iteration of `x` to render plots for.
#' @param x.over.time (`list` | NULL)\cr
#' List of vectors of x-variables, either specified via name or id.
#' If specified via names, also extra measurements from the opt.path can be
#' selected.
#' Maximum length for each vector is 5. For each list-element a line-plot iteration versus variable is generated.
#' If the vector has length > 2 only mean values per iteration are plotted as lines, if vector has length 1 every point is plotted.
#' Default is to plot all variables into as few plots as possible.
#' Note that discrete variables are converted to numeric, if specified in the same vector with numerics.
#' Moreover, if more than 1 point per iteration exists, mean values are calculated.
#' This is also done for factor variables! We recommend you to specify this argument in a useful way.
#' @param y.over.time (`list` | NULL)\cr
#' List of vectors of y-variables, either specified via name or id.
#' If specified via names, also extra measurements from the opt.path can be selected.
#' Maximum length for each vector is 5.
#' For each list-element a line-plot iteration versus variable is generated.
#' If the vector has length > 2 only mean values per iteration are plotted as lines, if vector has length 1 every point is plotted.
#' Default is to plot all variables into as few plots as possible.
#' Note that discrete variables are converted to numeric, if specified in the same vector with numerics.
#' Moreover, if more than 1 point per iteration exists, mean values are calculated.
#' This is also done for factor variables! We recommend you to specify this argument in a useful way.
#' @param contour.name (`character(1)` | NULL)\cr
#' It is possible to overlay the XSpace plot with an contour plot. This is
#' only possible, if the XSpace has exact 2 numeric and 0 discrete variable.
#' Consider subsetting your variables to use this feature! contour.name is the
#' name of the target variable that will be used for the contour lines.
#' Default is to use the first target variable, if it is possible to add
#' contour lines.
#' @template arg_opplotter_lims
#' @param alpha (`logical(1)`)\cr
#' Activates or deactivates the alpha fading for the plots. Default is `TRUE`.
#' @param log [character]\cr
#' Vector of variable names. All of this variable logarithmized in every plot.
#' Default is NULL - no logarithm is applied. Note that, if an variable has
#' only negative value, it is multiplied with -1. For variables with both
#' positive and negative values you have to do your own data preprocessing.
#' @param colours (`character(4)`)\cr
#' Colours of the points/lines for the four point types init, seq, prob and
#' marked. Default is red for init, blue for seq, green for prob and orange
#' for marked.
#' @param size.points (`numeric(4)` | NULL)\cr
#' Size of points in the plot, default is 3.
#' @param size.lines (`numeric(4)` | NULL)\cr
#' Size of lines in the plots, default is 1.5.
#' @param impute.scale (`numeric(1)`)\cr
#' Numeric missing values will be replaced by `max + impute.scale * (max - min)`.
#' Default is `1`.
#' @param impute.value (`character(1)`)\cr
#' Factor missing values will be replaced by `impute.value`. Default is `missing`.
#' @param scale (`character(1)`)\cr
#' Parameter `scale` from the function [GGally::ggparcoord()] which is used for
#' the multiD-case. Default is `std`.
#' @param ggplot.theme
#' Theme for the ggplots. Can be generated by [ggplot2::theme()]. Default is
#' `ggplot2::theme(legend.position = "top")`.
#' @param marked (`integer` | `character(1)` | NULL)\cr
#' \dQuote{best} or indices of points that should be marked in the plots.
#' If `marked = "best"` the best point for single crit optimization
#' respectively the pareto front for multi crit optimization is marked.
#' Default is `NULL` (no points are marked).
#' @param subset.obs [integer]\cr
#' Vector of indices to subset of observations to be plotted, default is all
#' observations. All indices must be available in the opt.path. But, to enable
#' subsetting over multiple iterations, not all indices must be available in
#' the current iteration. Indices not available in the current iteration will
#' be ignored. Default is all observations.
#' @param subset.vars (`integer` | `character`)\cr
#' Subset of variables (x-variables) to be plotted. Either vector of indices
#' or names. Default is all variables.
#' @param subset.targets (`integer` | `character`)\cr
#' Subset of target variables (y-variables) to be plotted. Either vector of
#' indices or names. Default is all variables
#' @param short.x.names [character]\cr
#' Short names for x variables that are used as axis labels. Note you can
#' only give shortnames for variables you are using in `subset.vars`
#' @param short.y.names [character]\cr
#' Short names for y variables that are used as axis labels. Note you can
#' only give shortnames for variables you are using in `subset.targets`
#' @param short.rest.names [character]\cr
#' Short names for rest variables that are used as axis labels. Note you can
#' only give shortnames for variables you are used in `x.over.time`
#' or `y.over.time`.
#' @return List of plots. List has up to elements:
#' plot.x: Plot for XSpace. If both X and Y are 1D, Plot for both
#' plot.y: Plot for YSpace. If both X and Y are 1D, NULL.
#' plot.x.over.time: List of plots for x over time. Can also be NULL.
#' plot.y.over.time: List of plots for y over time. Can also be NULL.
#' @export
renderOptPathPlot = function(op, iter, x.over.time, y.over.time, contour.name = NULL,
xlim = list(), ylim = list(), alpha = TRUE, log = NULL,
colours = c("red", "blue", "green", "orange"), size.points = 3, size.lines = 1.5, impute.scale = 1,
impute.value = "missing", scale = "std", ggplot.theme = ggplot2::theme(legend.position = "top"),
marked = NULL, subset.obs, subset.vars, subset.targets, short.x.names, short.y.names, short.rest.names) {
requirePackages(c("GGally", "ggplot2"), why = "renderOptPathPlot", default.method = "load")
iters.max = max(getOptPathDOB(op))
assertClass(op, "OptPath")
assertInt(iter, lower = 0L, upper = iters.max)
assertFlag(alpha)
assertCharacter(colours, len = 4L)
assertNumber(size.points)
assertNumber(size.points)
assertNumber(impute.scale)
assertCharacter(impute.value, len = 1L)
assertChoice(scale, choices = c("std", "robust", "uniminmax", "globalminmax", "center", "centerObs"))
assertClass(ggplot.theme, classes = c("theme", "gg"))
if (!is.null(marked)) {
if (is.character(marked)) {
if (marked != "best") {
stop("Marked must either be 'best' or an integerish vector.")
}
} else {
marked = asInteger(marked)
}
}
# Get Plotting Data and extract everything from the helper
data = getAndSubsetPlotData(op, iter, subset.obs, subset.vars, subset.targets,
marked, alpha, impute.scale, impute.value)
op.x = data$op.x
op.y = data$op.y
op.rest = data$op.rest
dob = data$dob
.alpha = data$.alpha
.type = data$.type
x.names = data$x.names
y.names = data$y.names
rest.names = data$rest.names
dim.x = length(data$x.names)
dim.y = length(data$y.names)
assertSubset(log, choices = c(x.names, y.names, rest.names))
# set defaults for the short names in x, y and rest
if (missing(short.x.names)) {
short.x.names = x.names
} else {
assertCharacter(short.x.names, len = dim.x)
}
if (missing(short.y.names)) {
short.y.names = y.names
} else {
assertCharacter(short.y.names, len = dim.y)
}
if (missing(short.rest.names)) {
short.rest.names = rest.names
} else {
assertCharacter(short.rest.names, len = length(rest.names))
}
# set and check x and y lims, if needed
lims = getOptPathLims(xlim, ylim, op.x, op.y, iter, 0)
xlim = lims$xlim
ylim = lims$ylim
# Set defaults for the over time plots or check the given params
if (missing(x.over.time)) {
x.over.time = split(x.names, rep(1:ceiling(dim.x / 5), each = 5,
length.out = dim.x))
} else {
if (!is.null(x.over.time)) {
if (!is.list(x.over.time)) {
x.over.time = list(x.over.time)
}
assertList(x.over.time)
for (vec in x.over.time) {
if (is.character(vec)) {
assertSubset(x = vec, choices = c(x.names, rest.names), empty.ok = FALSE)
} else {
assertNumeric(x = vec, lower = 1L, upper = dim.x, any.missing = FALSE, unique = TRUE)
}
}
}
}
if (missing(y.over.time)) {
y.over.time = split(y.names, rep(1:ceiling(dim.y / 5), each = 5,
length.out = dim.y))
} else {
if (!is.null(y.over.time)) {
if (!is.list(y.over.time)) {
y.over.time = list(y.over.time)
}
assertList(y.over.time)
for (vec in y.over.time) {
if (is.character(vec)) {
assertSubset(x = vec, choices = c(y.names, rest.names), empty.ok = FALSE)
} else {
assertNumeric(x = vec, lower = 1L, upper = dim.y, any.missing = FALSE, unique = TRUE)
}
}
}
}
if (!is.null(contour.name)) {
if (length(x.names) != 2 || any(apply(op.x, 2, class) != "numeric")) {
stop("Contour lines can only be applied if there are exacr 2 numeric x variables. Consider subsetting your variables.")
}
assertChoice(contour.name, y.names)
} else {
if (length(x.names) == 2 && all(apply(op.x, 2, class) == "numeric")) {
contour.name = y.names[1L]
}
}
# get classes of params (numeric or factor)
classes.x = BBmisc::vcapply(op.x, function(x) class(x))
classes.y = BBmisc::vcapply(op.y, function(x) class(x))
# So much for the data and the input, now the plots
# Special case: X and Y are 1D
if (dim.x == 1L && dim.y == 1L) {
pl1 = plot2D(cbind(x = op.x, y = op.y), .alpha, .type, log, names = c(x.names, y.names),
short.names = c(short.x.names, short.y.names), space = "both", iter = iter,
classes = c(classes.x, classes.y), xlim = xlim[["XSpace"]], ylim = xlim[["YSpace"]],
colours = colours, size = size.points, ggplot.theme = ggplot.theme)
pl2 = NULL
} else {
# plot 1: x-space
if (dim.x == 1L && classes.x == "numeric") {
pl1 = plot1DNum(op.x, .alpha, .type, log, names = x.names, short.names = short.x.names,
space = "x", iter = iter, xlim = xlim[["XSpace"]], colours = colours,
ggplot.theme = ggplot.theme)
}
if (dim.x == 1L && classes.x == "factor") {
pl1 = plot1DDisc(op.x, .alpha, .type, log, names = x.names, short.names = short.x.names,
space = "x", iter = iter, ylim = ylim[["XSpace"]], colours = colours,
ggplot.theme = ggplot.theme)
}
if (dim.x == 2L) {
pl1 = plot2D(op.x, .alpha, .type, log, names = x.names, short.names = short.x.names,
y.name = contour.name, op.y = op.y, space = "x", iter = iter, classes = classes.x, xlim = xlim[["XSpace"]],
ylim = ylim[["XSpace"]], colours = colours, size = size.points, ggplot.theme = ggplot.theme)
}
if (dim.x > 2L) {
pl1 = plotMultiD(op.x, .alpha, .type, log, names = x.names, short.names = short.x.names,
space = "x", iter = iter, colours = colours, size = size.lines, scale = scale,
ggplot.theme = ggplot.theme)
}
# plot 2: y-space
if (dim.y == 1L && classes.y == "numeric") {
pl2 = plot1DNum(op.y, .alpha, .type, log, names = y.names, short.names = short.y.names,
space = "y", iter = iter, xlim = xlim[["YSpace"]], colours = colours,
ggplot.theme = ggplot.theme)
}
if (dim.y == 1L && classes.y == "factor") {
pl2 = plot1DDisc(op.y, .alpha, .type, log, names = y.names, short.names = short.y.names,
space = "y", iter = iter, ylim = ylim[["YSpace"]], colours = colours,
ggplot.theme = ggplot.theme)
}
if (dim.y == 2L) {
pl2 = plot2D(op.y, .alpha, .type, log, names = y.names, short.names = short.y.names,
space = "y", iter = iter, classes = classes.y, xlim = xlim[["YSpace"]],
ylim = ylim[["YSpace"]], colours = colours, size = size.points, ggplot.theme = ggplot.theme)
}
if (dim.y > 2L) {
pl2 = plotMultiD(op.y, .alpha, .type, log, names = y.names, short.names = short.y.names,
space = "y", iter = iter, colours = colours, size = size.lines, scale = scale,
ggplot.theme = ggplot.theme)
}
}
# plot 3: x space over time
pl3 = vector(mode = "list", length = length(x.over.time))
for (i in seq_along(x.over.time)) {
# extract variable information from over.time
vars = x.over.time[[i]]
# if specified via character vector, convert to numeric
if (is.character(vars)) {
var.inds = which(c(names(op.x), names(op.rest)) %in% vars)
}
names = c(x.names, rest.names)[var.inds]
short.names = c(short.x.names, short.rest.names)[var.inds]
if (length(vars) == 1) {
pl3[[i]] = oneVariableOverTime(op = cbind(op.x, op.rest),
.alpha = .alpha, .type = .type, dob = dob, log = log,
names = names, short.names = short.names, iter = iter,
colours = colours, size.points = size.points,
size.lines = size.lines, ggplot.theme = ggplot.theme)
} else {
pl3[[i]] = multiVariablesOverTime(op = cbind(op.x, op.rest), .alpha = .alpha,
dob = dob, log = log, names = names, short.names = short.names, space = "XSpace",
iter = iter, colours = colours, ggplot.theme = ggplot.theme)
}
}
if (length(pl3) == 0) {
pl3 = NULL
}
# plot 4: y space over time
pl4 = vector(mode = "list", length = length(y.over.time))
for (i in seq_along(y.over.time)) {
# extract variable information from over.time
vars = y.over.time[[i]]
# if specified via character vector, convert to numeric
if (is.character(vars)) {
var.inds = which(c(names(op.y), names(op.rest)) %in% vars)
}
names = c(y.names, rest.names)[var.inds]
short.names = c(short.y.names, short.rest.names)[var.inds]
if (length(vars) == 1) {
pl4[[i]] = oneVariableOverTime(op = cbind(op.y, op.rest),
.alpha = .alpha, .type = .type, dob = dob, log = log,
names = names, short.names = short.names, iter = iter,
colours = colours, size.points = size.points,
size.lines = size.lines, ggplot.theme = ggplot.theme)
} else {
pl4[[i]] = multiVariablesOverTime(op = cbind(op.y, op.rest), .alpha = .alpha,
dob = dob, log = log, names = names, short.names = short.names, space = "YSpace",
iter = iter, colours = colours, ggplot.theme = ggplot.theme)
}
}
if (length(pl4) == 0) {
pl4 = NULL
}
return(list(plot.x = pl1, plot.y = pl2, plot.x.over.time = pl3, plot.y.over.time = pl4))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.