From 39fda795451b6ab4b01662ccbeede934f9aadf0a Mon Sep 17 00:00:00 2001 From: Bernd Bischl Date: Thu, 17 Oct 2024 18:02:11 +0200 Subject: [PATCH 1/3] .. --- R/LossFunction.R | 36 +-- R/Objective.R | 128 ++++---- R/Visualizer1D.R | 113 ------- R/Visualizer1DFun.R | 129 ++++++++ R/Visualizer1DModel.R | 50 ++-- ...ualizer1DObjective.R => Visualizer1DObj.R} | 38 +-- R/Visualizer2D.R | 276 ------------------ R/Visualizer2DFun.R | 100 +++++++ R/Visualizer2DModel.R | 3 +- ...ualizer2DObjective.R => Visualizer2DObj.R} | 3 +- R/VisualizerLossFunction.R | 122 -------- R/VisualizerLossFuns.R | 79 +++++ R/as_visualizer.R | 59 ---- test.R | 35 +++ 14 files changed, 472 insertions(+), 699 deletions(-) delete mode 100644 R/Visualizer1D.R create mode 100644 R/Visualizer1DFun.R rename R/{Visualizer1DObjective.R => Visualizer1DObj.R} (67%) delete mode 100644 R/Visualizer2D.R create mode 100644 R/Visualizer2DFun.R rename R/{Visualizer2DObjective.R => Visualizer2DObj.R} (99%) delete mode 100644 R/VisualizerLossFunction.R create mode 100644 R/VisualizerLossFuns.R create mode 100644 test.R diff --git a/R/LossFunction.R b/R/LossFunction.R index d3a74c5..703c32d 100644 --- a/R/LossFunction.R +++ b/R/LossFunction.R @@ -1,3 +1,5 @@ +#FIXME: doc API of funs better + #' @title Loss Function #' @@ -22,7 +24,7 @@ LossFunction = R6::R6Class("LossFunction", #' @field properties `character()`\cr #' Additional properties of the loss function. - properties = NULL, + task_type = NULL, #' @description #' Creates a new instance of this [R6][R6::R6Class] class. @@ -35,11 +37,11 @@ LossFunction = R6::R6Class("LossFunction", #' Additional properties of the loss function. #' @param fun (`function(y_true, y_pred, ...)`)\cr #' Loss function. - initialize = function(id, label, properties, fun) { + initialize = function(id, label, task_type, fun) { self$id = assert_character(id) - self$fun = assert_function(fun) self$label = assert_character(label) - self$properties = assert_character(properties) + self$task_type = assert_choice(task_type, c("regr", "classif")) + self$fun = assert_function(fun) } ) ) @@ -68,29 +70,29 @@ lss = function(.key, ...) { dict_loss$get(.key, ...) } -dict_loss$add("l2_se", LossFunction$new("l2_se", "L2 Squared Error", "regr", function(y_true, y_pred) { - (y_true - y_pred)^2 +dict_loss$add("l2_se", LossFunction$new("l2", "L2 Squared Error", "regr", function(r) { + (r)^2 })) -dict_loss$add("l1_ae", LossFunction$new("l1_ae", "L1 Absolute Error", "regr", function(y_true, y_pred) { - abs(y_true - y_pred) +dict_loss$add("l1_ae", LossFunction$new("l1", "L1 Absolute Error", "regr", function(r) { + abs(r) })) -dict_loss$add("huber", LossFunction$new("huber", "Huber Loss", "regr", function(y_true, y_pred, delta = 1) { - a = abs(y_true - y_pred) +dict_loss$add("huber", LossFunction$new("huber", "Huber Loss", "regr", function(r, delta = 1) { + a = abs(r) ifelse(a <= delta, 0.5 * a^2, delta * a - delta^2 / 2) })) -dict_loss$add("log-cosh", LossFunction$new("log-cosh", "Log-Cosh Loss", "regr", function(y_true, y_pred) { - log(cosh(y_pred - y_true)) +dict_loss$add("log-cosh", LossFunction$new("logcosh", "Log-Cosh Loss", "regr", function(r) { + log(cosh(r)) })) -dict_loss$add("cross-entropy", LossFunction$new("cross-entropy", "Cross-Entropy", "classif", function(y_true, y_pred) { - log(1 + exp(-y_true * y_pred)) +dict_loss$add("cross-entropy", LossFunction$new("logloss", "Log Loss", "classif", function(r) { + log(1 + exp(-r)) })) -dict_loss$add("hinge", LossFunction$new("hinge", "Hinge Loss", "classif", function(y_true, y_pred) { - pmax(1 - y_true * y_pred, 0) +dict_loss$add("hinge", LossFunction$new("hinge", "Hinge Loss", "classif", function(r) { + pmax(1 - r, 0) })) @@ -101,7 +103,7 @@ as.data.table.DictionaryLoss = function(x, ..., objects = FALSE) { setkeyv(map_dtr(x$keys(), function(key) { t = x$get(key) insert_named( - list(key = key, label = t$label, properties = list(t$properties)), + list(key = key, label = t$label, task_type = t$task_type), if (objects) list(object = list(t)) ) }, .fill = TRUE), "key")[] diff --git a/R/Objective.R b/R/Objective.R index 226804e..ae7c44f 100644 --- a/R/Objective.R +++ b/R/Objective.R @@ -13,11 +13,11 @@ Objective = R6::R6Class("Objective", #' @field label (`character(1)` The label of the objective, i.e. a. label = NULL, - #' @field limits_lower (`numeric()`) The lower limits for each dimension. - limits_lower = NA, + #' @field lower (`numeric()`) The lower limits for each dimension. + lower = NA, - #' @field limits_upper (`numeric()`) The upper limits for each dimension. - limits_upper = NA, + #' @field upper (`numeric()`) The upper limits for each dimension. + upper = NA, #' @field minimize (`logical(1)`) Is the problem a minimization problem? minimize = FALSE, @@ -30,21 +30,21 @@ Objective = R6::R6Class("Objective", #' @param fun (`function` The objective function. The first argument must be a numerical input of length `xdim`. #' @param label (`character(1)` The label of the objective, i.e. a. #' @param xdim (`integer(1)`) The input dimension of `fun`. Use `xdim = NA` for an arbitrary input dimension. - #' @param limits_lower (`numeric(xdim)`) The lower boundaries for inputs to `fun`. Must - #' @param limits_upper (`numeric(xdim)`) The upper boundaries for inputs to `fun`. Must + #' @param lower (`numeric(xdim)`) The lower boundaries for inputs to `fun`. Must + #' @param upper (`numeric(xdim)`) The upper boundaries for inputs to `fun`. Must #' be of length `xdim`. #' @param xtest (`numeric()`) Test value for `fun` during initialization. If not defined, #' `xtest = rep(0, ifelse(is.na(xdim), 2, xdim))` is used. #' @param minimize (`logical(1)`) Is the problem a minimization problem? Default is no (`FALSE`). #' @param ... Additional arguments passed to `fun`. - initialize = function(id, fun, label = "f", xdim, limits_lower = NA, - limits_upper = NA, xtest = NULL, minimize = FALSE, ...) { + initialize = function(id, fun, label = "f", xdim, lower = NA, + upper = NA, xtest = NULL, minimize = FALSE, ...) { - self$id = checkmate::assertString(id) - self$label = checkmate::assertString(label) - self$minimize = checkmate::assertLogical(minimize, len = 1L) - private$p_fun = checkmate::assertFunction(fun) - private$p_xdim = checkmate::assertCount(xdim, na.ok = TRUE, positive = TRUE, coerce = TRUE) + self$id = assertString(id) + self$label = assertString(label) + self$minimize = assertLogical(minimize, len = 1L) + private$p_fun = assertFunction(fun) + private$p_xdim = assertCount(xdim, na.ok = TRUE, positive = TRUE, coerce = TRUE) private$p_fargs = list(...) if ("x" %in% names(private$p_fargs)) { @@ -57,11 +57,11 @@ Objective = R6::R6Class("Objective", xtest = rep(0, ifelse(is.na(xdim), 2, xdim)) } private$p_xtest = self$assertX(xtest) - checkmate::assertNumber(self$eval(xtest)) # check that fun works as expected + assertNumber(self$eval(xtest)) # check that fun works as expected self$addLogFun(function(x, fval, grad) l2norm(grad), "gnorm") - if (! is.na(limits_lower[1])) self$limits_lower = self$assertX(limits_lower) - if (! is.na(limits_upper[1])) self$limits_upper = self$assertX(limits_upper) + if (! is.na(lower[1])) self$lower = self$assertX(lower) + if (! is.na(upper[1])) self$upper = self$assertX(upper) return(invisible(self)) }, @@ -72,7 +72,7 @@ Objective = R6::R6Class("Objective", #' @return The result of `fun(x)`. eval = function(x) { if (! is.na(private$p_xdim)) { - checkmate::assertNumeric(x, len = private$p_xdim) + assertNumeric(x, len = private$p_xdim) } return(do.call(private$p_fun, c(list(x = x), private$p_fargs))) }, @@ -85,7 +85,7 @@ Objective = R6::R6Class("Objective", #' @return Invisible list of logs that are added to the archive. evalStore = function(x) { if (! is.na(private$p_xdim)) { - checkmate::assertNumeric(x, len = private$p_xdim) + assertNumeric(x, len = private$p_xdim) } fval = self$eval(x) grad = self$grad(x) @@ -102,12 +102,12 @@ Objective = R6::R6Class("Objective", #' @description Assert a numeric input if it is suitable or not. #' @param x (`numeric()`) Input value for `fun`. - #' @param ... Additional arguments passed to `checkmate::assertNumeric(...)`. + #' @param ... Additional arguments passed to `assertNumeric(...)`. assertX = function(x, ...) { if (is.na(private$p_xdim)) { - return(checkmate::assertNumeric(x, ...)) + return(assertNumeric(x, ...)) } else { - return(checkmate::assertNumeric(x, len = private$p_xdim, ...)) + return(assertNumeric(x, len = private$p_xdim, ...)) } }, @@ -142,7 +142,7 @@ Objective = R6::R6Class("Objective", #' @param label (`character(1)`) The name of the logger. #' @param ... Additional arguments passed to `fun`. addLogFun = function(l, label) { - checkmate::assertFunction(l, c("x", "fval", "grad")) + assertFunction(l, c("x", "fval", "grad")) xtest = private$p_xtest testfval = self$eval(xtest) testgrad = self$grad(xtest) @@ -152,11 +152,11 @@ Objective = R6::R6Class("Objective", } else { checked = FALSE if (is.numeric(e)) { - checkmate::assertNumber(e) + assertNumber(e) checked = TRUE } if (is.character(e) || is.factor(e)) { - checkmate::assertString(as.character(e)) + assertString(as.character(e)) } if (! checked) { stop("Function did not return a single numerical value or string of length one") @@ -232,43 +232,43 @@ l2norm = function(x) sqrt(sum(crossprod(x))) dict_objective = R6::R6Class("DictionaryObjective", inherit = mlr3misc::Dictionary, cloneable = FALSE)$new() -tfuns = c(list(list(minimize = TRUE, name = "branin", desc = "A function. 2 dimensional function.", xdim = 2, limits_lower = c(-2, -2), limits_upper = c(3, 3))), - list(list(minimize = TRUE, name = "borehole", desc = "A function estimating water flow through a borehole. 8 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1.5, 1))), - list(list(minimize = FALSE, name = "franke", desc = "A function. 2 dimensional function.", xdim = 2, limits_lower = c(-0.5, -0.5), limits_upper = c(1, 1))), - list(list(minimize = FALSE, name = "zhou1998", desc = "A function. 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = TRUE, name = "currin1991", desc = "A function. 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), +tfuns = c(list(list(minimize = TRUE, name = "branin", desc = "A function. 2 dimensional function.", xdim = 2, lower = c(-2, -2), upper = c(3, 3))), + list(list(minimize = TRUE, name = "borehole", desc = "A function estimating water flow through a borehole. 8 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1.5, 1))), + list(list(minimize = FALSE, name = "franke", desc = "A function. 2 dimensional function.", xdim = 2, lower = c(-0.5, -0.5), upper = c(1, 1))), + list(list(minimize = FALSE, name = "zhou1998", desc = "A function. 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = TRUE, name = "currin1991", desc = "A function. 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), # lim2002 no longer available as of 2024-03-25 - # list(list(minimize = FALSE, name = "lim2002", desc = "Some function? 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = FALSE, name = "banana", desc = "A banana shaped function. 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = FALSE, name = "sinumoid", desc = "A sinusoid added to a sigmoid function. 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = FALSE, name = "waterfall", desc = "A sinusoid added to a sigmoid function. 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = TRUE, name = "GoldsteinPrice", desc = "Goldstein-Price function. Exponential scale, you might want to use GoldsteinPriceLog instead 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = TRUE, name = "GoldsteinPriceLog", desc = "Goldstein-Price function on a log scale. 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = TRUE, name = "beale", desc = "Beale function 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = TRUE, name = "easom", desc = "Easom function 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = TRUE, name = "hump", desc = "Hump function 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = FALSE, name = "quad_peaks", desc = "quad_peaks function 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = FALSE, name = "quad_peaks_slant", desc = "quad_peaks_slant function 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = TRUE, name = "ackley", desc = "Ackley function. 2 dimensional function.", xdim = 2, limits_lower = c(0, 0), limits_upper = c(1, 1))), - list(list(minimize = FALSE, name = "gaussian1", desc = "A Gaussian function centered at 0.5. Any dimensional function.", xdim = NA, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "sqrtsin", desc = "A square root of a sine function. Any dimensional function.", xdim = NA, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "powsin", desc = "A sine function raised to a power keeping its original sign. Any dimensional function.", xdim = NA, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "OTL_Circuit", desc = "OTL Circuit. 6 dimensional function.", xdim = 6, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "piston", desc = "Piston simulation function. 7 dimensional function", xdim = 7, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "wingweight", desc = "Wing weight function. 10 dimensional function.", xdim = 10, limits_lower = NA, limits_upper = NA)), - #list(list(minimize = FALSE, name = "welch", desc = "Welch et al (1992) function. 20 dimensional function.", xdim = 20, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "robotarm", desc = "Robot arm function. 8 dimensional function.", xdim = 8, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "RoosArnold", desc = "Roos & Arnold (1963) function. d dimensional function.", xdim = NA, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "Gfunction", desc = "G-function d dimensional function.", xdim = NA, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "griewank", desc = "Griewank function n dimensional function.", xdim = NA, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "levy", desc = "Levy function n dimensional function.", xdim = NA, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "michalewicz", desc = "Michalewicz function n dimensional function.", xdim = NA, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "rastrigin", desc = "Rastrigin function n dimensional function.", xdim = NA, limits_lower = NA, limits_upper = NA)), - #list(list(minimize = FALSE, name = "moon_high", desc = "Moon (2010) high-dimensional function for screening 20 dimensional function.", xdim = 20, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "linkletter_nosignal", desc = "Linkletter (2006) no signal function, just returns zero d dimensional function.", xdim = NA, limits_lower = NA, limits_upper = NA)), - #list(list(minimize = FALSE, name = "Morris", desc = "Morris function 20 dimensional function.", xdim = 20, limits_lower = NA, limits_upper = NA)), - #list(list(minimize = FALSE, name = "detpep8d", desc = "detpep8d function 8 dimensional function.", xdim = 8, limits_lower = NA, limits_upper = NA)), - list(list(minimize = FALSE, name = "hartmann", desc = "hartmann function 6 dimensional function.", xdim = 6, limits_lower = NA, limits_upper = NA))) + # list(list(minimize = FALSE, name = "lim2002", desc = "Some function? 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = FALSE, name = "banana", desc = "A banana shaped function. 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = FALSE, name = "sinumoid", desc = "A sinusoid added to a sigmoid function. 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = FALSE, name = "waterfall", desc = "A sinusoid added to a sigmoid function. 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = TRUE, name = "GoldsteinPrice", desc = "Goldstein-Price function. Exponential scale, you might want to use GoldsteinPriceLog instead 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = TRUE, name = "GoldsteinPriceLog", desc = "Goldstein-Price function on a log scale. 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = TRUE, name = "beale", desc = "Beale function 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = TRUE, name = "easom", desc = "Easom function 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = TRUE, name = "hump", desc = "Hump function 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = FALSE, name = "quad_peaks", desc = "quad_peaks function 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = FALSE, name = "quad_peaks_slant", desc = "quad_peaks_slant function 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = TRUE, name = "ackley", desc = "Ackley function. 2 dimensional function.", xdim = 2, lower = c(0, 0), upper = c(1, 1))), + list(list(minimize = FALSE, name = "gaussian1", desc = "A Gaussian function centered at 0.5. Any dimensional function.", xdim = NA, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "sqrtsin", desc = "A square root of a sine function. Any dimensional function.", xdim = NA, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "powsin", desc = "A sine function raised to a power keeping its original sign. Any dimensional function.", xdim = NA, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "OTL_Circuit", desc = "OTL Circuit. 6 dimensional function.", xdim = 6, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "piston", desc = "Piston simulation function. 7 dimensional function", xdim = 7, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "wingweight", desc = "Wing weight function. 10 dimensional function.", xdim = 10, lower = NA, upper = NA)), + #list(list(minimize = FALSE, name = "welch", desc = "Welch et al (1992) function. 20 dimensional function.", xdim = 20, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "robotarm", desc = "Robot arm function. 8 dimensional function.", xdim = 8, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "RoosArnold", desc = "Roos & Arnold (1963) function. d dimensional function.", xdim = NA, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "Gfunction", desc = "G-function d dimensional function.", xdim = NA, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "griewank", desc = "Griewank function n dimensional function.", xdim = NA, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "levy", desc = "Levy function n dimensional function.", xdim = NA, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "michalewicz", desc = "Michalewicz function n dimensional function.", xdim = NA, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "rastrigin", desc = "Rastrigin function n dimensional function.", xdim = NA, lower = NA, upper = NA)), + #list(list(minimize = FALSE, name = "moon_high", desc = "Moon (2010) high-dimensional function for screening 20 dimensional function.", xdim = 20, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "linkletter_nosignal", desc = "Linkletter (2006) no signal function, just returns zero d dimensional function.", xdim = NA, lower = NA, upper = NA)), + #list(list(minimize = FALSE, name = "Morris", desc = "Morris function 20 dimensional function.", xdim = 20, lower = NA, upper = NA)), + #list(list(minimize = FALSE, name = "detpep8d", desc = "detpep8d function 8 dimensional function.", xdim = 8, lower = NA, upper = NA)), + list(list(minimize = FALSE, name = "hartmann", desc = "hartmann function 6 dimensional function.", xdim = 6, lower = NA, upper = NA))) for (i in seq_along(tfuns)) { tf = tfuns[[i]] @@ -289,8 +289,8 @@ for (i in seq_along(tfuns)) { suppressWarnings(dict_objective$add( id, Objective$new( fun = cl_fun, - id = id, label = tf$name, xdim = tf$xdim, limits_lower = tf$limits_lower, - limits_upper = tf$limits_upper + id = id, label = tf$name, xdim = tf$xdim, lower = tf$lower, + upper = tf$upper ) )) } @@ -317,8 +317,8 @@ as.data.table.DictionaryObjective = function(x, ..., objects = FALSE) { data.table::setkeyv(mlr3misc::map_dtr(x$keys(), function(key) { t = x$get(key) mlr3misc::insert_named( - c(list(key = key, label = t$label, xdim = t$xdim, limits_lower = list(t$limits_lower), - limits_upper = list(t$limits_upper))), if (objects) list(object = list(t)) + c(list(key = key, label = t$label, xdim = t$xdim, lower = list(t$lower), + upper = list(t$upper))), if (objects) list(object = list(t)) ) }, .fill = TRUE), "key")[] } diff --git a/R/Visualizer1D.R b/R/Visualizer1D.R deleted file mode 100644 index a8e9a3e..0000000 --- a/R/Visualizer1D.R +++ /dev/null @@ -1,113 +0,0 @@ -#' @title Visualize Base Class -#' -#' @description -#' This class is used to create 1D visualizations. -#' -#' @template param_x1_limits -#' @template param_x2_limits -#' @template param_padding -#' @template param_n_points -#' -#' @export -Visualizer1D = R6::R6Class("Visualizer1D", - public = list( - - #' @field x (`vector()`)\cr - #' x-values. - x = NULL, - - #' @field y (`vector()`)\cr - #' y-values - y = NULL, - - #' @field plot_lab (character(1)\cr - #' Label of the plot. - plot_lab = NULL, - - #' @field x_lab (character(1)\cr - #' Label of the x axis. - x_lab = NULL, - - #' @field y_lab (character(1)\cr - #' Label of the y axis. - y_lab = NULL, - - #' @description - #' Creates a new instance of this [R6][R6::R6Class] class. - #' - #' @param x (`numeric()`)\cr - #' x-values. - #' @param y (`numeric()`)\cr - #' y-values. - #' @param plot_lab (character(1)\cr - #' Label of the plot. - #' @param x_lab (character(1)\cr - #' Label of the x axis. - #' @param y_lab (character(1)\cr - #' Label of the y axis. - initialize = function(x, y, plot_lab = NULL, x_lab = "x", y_lab = "y") { - self$x = assert_numeric(x) - self$y = assert_numeric(y) - self$plot_lab = assert_character(plot_lab, null.ok = TRUE) - self$x_lab = assert_character(x_lab) - self$y_lab = assert_character(y_lab) - return(invisible(self)) - }, - - #' @description - #' Initialize the plot with a line plot. - #' - #' @param ... (`any`)\cr - #' Further arguments passed to `add_trace(...)`. - init_layer_lines = function(...) { - private$.plot = plot_ly() %>% - add_trace( - name = self$plot_lab, - showlegend = FALSE, - x = self$x, - y = self$y, - type = "scatter", - mode = "lines", - ... - ) %>% - layout( - title = self$plot_lab, - xaxis = list(title = self$x_lab), - yaxis = list(title = self$y_lab)) - - return(invisible(self)) - }, - - #' @description - #' Set the layout of the plotly plot. - #' - #' @param ... (`any`)\cr - #' Layout options directly passed to `layout(...)`. - setLayout = function(...) { - private$p_layout = list(...) - private$p_plot = private$p_plot %>% layout(...) - - return(invisible(self)) - }, - - #' @description - #' Return the plot and hence plot it or do further processing. - plot = function() { - if (is.null(private$.plot)) self$init_layer_lines() - return(private$.plot) - }, - - #' @description - #' Save the plot by using plotlys `orca()` function. - #' - #' @param ... (`any`)\cr - #' Further arguments passed to `orca()`. - save = function(...) { - orca(private$.plot, ...) - } - ), - - private = list( - .plot = NULL - ) -) diff --git a/R/Visualizer1DFun.R b/R/Visualizer1DFun.R new file mode 100644 index 0000000..8a04b9c --- /dev/null +++ b/R/Visualizer1DFun.R @@ -0,0 +1,129 @@ +#' @title Visualize Base Class +#' +#' @description +#' This class is used to create 1D visualizations. +#' +#' @template param_x1_limits +#' @template param_x2_limits +#' @template param_padding +#' @template param_n_points +#' +#' @export +Visualizer1DFun = R6::R6Class("Visualizer1DFun", + public = list( + + #' @field x (`numeric(n)`)\cr + #' x-values of function + fun_x = NULL, + + #' @field y (`numeric(n)`)\cr + #' y-values of function + fun_y = NULL, + + #' @field title (character(1)\cr + #' Title of plot + title = NULL, + + #' @field lab_x (character(1)\cr + #' Label of x-axis + lab_x = NULL, + # FIXME: make consistent names with other visualizers + + #' @field lab_y (character(1)\cr + #' Label of y-axis + lab_y = NULL, + + #' @field x (`numeric(m)`)\cr + #' x-values of extra points to plot. + #' Use NULL if no points should be plotted. + points_x = NULL, + + #' @field y (`numeric(m)`)\cr + #' y-values of extra points to plot. + #' Use NULL if no points should be plotted. + points_y = NULL, + + #' @field line_col (character(1)\cr + #' Color of plotted line + line_col = NULL, + + #' @field line_width (numeric(1)\cr + #' Width of plotted line + line_width = NULL, + + #' @field line_type (character(1)\cr + #' Type of plotted line + line_type = NULL, + + #' @field points_col (character(1)\cr + #' Color of plotted points + points_col = NULL, + + #' @field points_size (numeric(1)\cr + #' Size of plotted points + points_size = NULL, + + #' @field points_shape (integer(1)\cr + #' Shape of plotted points + points_shape = NULL, + + #' @field points_alpha (numeric(1)\cr + #' Alpha blending of plotted points + points_alpha = NULL, + + #FIXME: add point-size, point col, point-symbol + + #' @description + #' Creates a new instance of this [R6][R6::R6Class] class. + #' + #' @param x (`numeric()`)\cr + #' x-values of function + #' @param y (`numeric()`)\cr + #' y-values of function + #' @param title (character(1)\cr + #' Title of plot + #' @param lab_x (character(1)\cr + #' Label of x-axis + #' @param lab_y (character(1)\cr + #' Label of y-axis + #' @param points_x (`numeric()`)\cr + #' x-values of extra points to plot. + #' Use NULL if no points should be plotted. + #' @param points_y (`numeric()`)\cr + #' y-values of extra points to plot. + #' Use NULL if no points should be plotted. + initialize = function(fun_x, fun_y, title = NULL, lab_x = "x", lab_y = "y", points_x = NULL, points_y = NULL) { + self$fun_x = assert_numeric(fun_x) + self$fun_y = assert_numeric(fun_y) + self$title = assert_character(title, null.ok = TRUE) + self$lab_x = assert_character(lab_x) + self$lab_y = assert_character(lab_y) + self$points_x = assert_numeric(points_x, null.ok = TRUE) + self$points_y = assert_numeric(points_y, null.ok = TRUE) + self$line_type = "solid" + self$line_col = "red" + self$line_width = 3 + self$points_shape = 19 + self$points_col = "black" + self$points_size = 2 + self$points_alpha = 0.3 + return(invisible(self)) + }, + + # FIXME: set better defaults here to make plot nicer, maybe ask lukas + + plot = function() { + dd = data.frame(x = self$fun_x, y = self$fun_y) + pl = ggplot(data = dd, aes(x = x, y = y)) + pl = pl + geom_line(size = self$line_width, col = self$line_col, linetype = self$line_type) + # use specified axis labels and legend title + pl = pl + labs(title = self$title, x = self$lab_x, y = self$lab_y) + if (!is.null(self$points_x)) { + dd2 = data.frame(x = self$points_x, y = self$points_y) + pl = pl + geom_point(data = dd2, size = self$points_size, col = self$points_col, + shape = self$points_shape, alpha = self$points_alpha) + } + return(pl) + } + ) +) diff --git a/R/Visualizer1DModel.R b/R/Visualizer1DModel.R index 1c39562..0c4a0fd 100644 --- a/R/Visualizer1DModel.R +++ b/R/Visualizer1DModel.R @@ -1,3 +1,4 @@ +# FIXME: check that this works with all classif output types #' @title Visualize Model #' @@ -5,12 +6,10 @@ #' This class is used to create visualizations of tasks and learners. #' #' @template param_x1_limits -#' @template param_padding #' @template param_n_points #' #' @export -Visualizer1DModel = R6::R6Class("Visualizer1DModel", - inherit = Visualizer1D, +Visualizer1DModel = R6::R6Class("Visualizer1DModel", inherit = Visualizer1DFun, public = list( #' @field task (`mlr3::Task`)\cr @@ -21,6 +20,11 @@ Visualizer1DModel = R6::R6Class("Visualizer1DModel", #' Learner used to train the model. learner = NULL, + # FIXME: add that we can plot data + plot_data = NULL, + + n_points = NULL, + #' @description #' Creates a new instance of this [R6][R6::R6Class] class. #' @@ -28,30 +32,38 @@ Visualizer1DModel = R6::R6Class("Visualizer1DModel", #' The task to train the model on. #' @param learner ([mlr3::Learner])\cr #' The learner to train the model with. - initialize = function(task, learner, x1_limits = NULL, padding = 0, n_points = 100L) { + initialize = function(task, learner, plot_data = FALSE, xlim = NULL, n_points = 100) { + # FIXME: doc complete class, not all args are doced here self$task = assert_task(task) + fnames = task$feature_names + if (length(fnames) != 1) + stop("Task must have exactly 1 feature") self$learner = assert_learner(learner, task = self$task) - assert_numeric(x_limits, len = 2, null.ok = TRUE) + assert_flag(plot_data) assert_count(n_points) - x_lab = self$task$feature_names[1] - data = task$data() + + # train learner on task self$learner$train(task) - xlimits = range(data[, x_lab, with = FALSE]) - x = seq(xlimits[1] - padding, xlimits[2] + padding, length.out = n_points) + x_train = task$data()[[fnames[1]]] + y_train = task$truth() - newdata = set_names(as.data.table(x), self$task$feature_names) - y = self$learner$predict_newdata(newdata)$response + if (is.null(xlim)) + xlim = range(x_train) + x_pred = seq(xlim[1], xlim[2], length.out = n_points) + newdata = set_names(as.data.table(x_pred), self$task$feature_names) + y_pred = self$learner$predict_newdata(newdata)$response + title = sprintf("%s on %s", self$learner$id, self$task$id) - super$initialize( - x = x, - y = y, - plot_lab = sprintf("%s on %s", self$learner$id, self$task$id), - x_lab = x_lab, - y_lab = task$target_names - ) + points_x = NULL; points_y = NULL + if (plot_data) { + points_x = x_train + points_y = y_train + } - return(invisible(self)) + super$initialize(fun_x = x_pred, fun_y = y_pred, + title = title, lab_x = fnames[1], lab_y = task$target_names, + points_x = points_x, points_y = points_y) } ) ) diff --git a/R/Visualizer1DObjective.R b/R/Visualizer1DObj.R similarity index 67% rename from R/Visualizer1DObjective.R rename to R/Visualizer1DObj.R index 5ad7acf..13a38b1 100644 --- a/R/Visualizer1DObjective.R +++ b/R/Visualizer1DObj.R @@ -1,3 +1,7 @@ +#FIXME: run rcmd check +# FIXME: think about plotting extra points +# FIXME: can we add optimizer traces? maybe use bbotk? + #' @title Visualize Objective #' #' @description @@ -8,8 +12,7 @@ #' @template param_n_points #' #' @export -Visualizer1DObjective = R6::R6Class("Visualizer1DObjective", - inherit = Visualizer1D, +Visualizer1DObj = R6::R6Class("Visualizer1DObj", inherit = Visualizer1DFun, public = list( #' @field objective (`Objective`)\cr @@ -23,35 +26,20 @@ Visualizer1DObjective = R6::R6Class("Visualizer1DObjective", #' @param objective (`Objective`)\cr #' The objective which was optimized. #' This object is used to generate the surface/contour lines. - initialize = function(objective, x1_limits = NULL, padding = 0, n_points = 100L) { + initialize = function(objective, xlim = NULL, n_points = 100L) { self$objective = assert_r6(objective, "Objective") - assert_numeric(x_limits, len = 2, null.ok = TRUE) - assert_numeric(padding) - assert_count(n_points) - if (objective$xdim != 1) { stopf("`Visualizer1D` requires 1-dimensional inputs, but `objective$xdim = %s`", objective$xdim) } - - x_limits = x_limits %??% c(objective$limits_lower, objective$limits_upper) - - if (any(is.na(x_limits))) { - stop("Limits could not be extracted from the objective. Please use `x_limits`.") - } - - x_pad = (x_limits[2] - x_limits[1]) * padding - x = seq(x_limits[1] - x_pad, x_limits[2] + x_pad, length.out = n_points) + xlim = xlim %??% c(objective$lower, objective$upper) + if (any(is.na(xlim))) + stop("Limits could not be extracted from the objective. Please use `xlim`.") + assert_numeric(xlim, len = 2) + assert_count(n_points) + x = seq(xlim[1], xlim[2], length.out = n_points) y = map_dbl(x, function(x) objective$eval(x)) - super$initialize( - x = x, - y = y, - plot_lab = self$objective$label, - x_lab = "x", - y_lab = "y" - ) - - return(invisible(self)) + super$initialize(fun_x = x, fun_y = y, title = self$objective$label, lab_x = "x", lab_y = "y") }, #' @description diff --git a/R/Visualizer2D.R b/R/Visualizer2D.R deleted file mode 100644 index 8ce80fe..0000000 --- a/R/Visualizer2D.R +++ /dev/null @@ -1,276 +0,0 @@ -#' @title Visualize Base Class -#' -#' @description -#' This class is used to create 2D visualizations. -#' -#' @template param_x1_limits -#' @template param_x2_limits -#' @template param_padding -#' @template param_n_points -#' -#' @export -Visualizer2D = R6::R6Class("Visualizer2D", - public = list( - - #' @field grid (`list()`)\cr - #' List with the `x1` and `x2` grid. - grid = NULL, - - #' @field zmat (`matrix()`)\cr - #' The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`. - zmat = NULL, - - #' @field plot_lab (character(1)\cr - #' Label of the plot. - plot_lab = NULL, - - #' @field x1_lab (character(1)\cr - #' Label of the x1 axis. - x1_lab = NULL, - - #' @field x2_lab (character(1)\cr - #' Label of the x2 axis. - x2_lab = NULL, - - #' @field z_lab (character(1)\cr - #' Label of the z axis. - z_lab = NULL, - - #' @description - #' Creates a new instance of this [R6][R6::R6Class] class. - #' - #' @param grid (`list()`)\cr - #' List with the `x1` and `x2` grid. - #' @param zmat (`matrix()`)\cr - #' The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`. - #' @param plot_lab (`character(1)`)\cr - #' Label of the plot. - #' @param x1_lab (`character(1)`)\cr - #' Label of the x1 axis. - #' @param x2_lab (`character(1)`)\cr - #' Label of the x2 axis. - #' @param z_lab (`character(1)`)\cr - #' Label of the z axis. - initialize = function(grid, zmat, plot_lab = NULL, x1_lab = "x1", x2_lab = "x2", z_lab = "z") { - self$grid = assert_list(grid) - self$zmat = assert_matrix(zmat) - self$plot_lab = assert_character(plot_lab, null.ok = TRUE) - self$x1_lab = assert_character(x1_lab) - self$x2_lab = assert_character(x2_lab) - self$z_lab = assert_character(z_lab) - return(invisible(self)) - }, - - #' @description - #' Initialize the plot with contour lines. - #' - #' @param opacity (`numeric(1)`)\cr - #' Opacity of the layer. - #' @param colorscale (`list()`)\cr - #' The coloring of the contour. - #' @param show_title (`logical(1)`)\cr - #' Indicator whether to show the title of the plot. - #' @param ... (`any`)\cr - #' Further arguments passed to `add_trace(...)`. - init_layer_contour = function(opacity = 0.8, colorscale = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), show_title = TRUE, ...) { - assert_number(opacity, lower = 0, upper = 1) - assert_list(colorscale) - assert_flag(show_title) - - private$.vbase = c(as.list(environment()), list(...)) - private$.layer_primary = "contour" - - llp = list(x = self$grid$x1, y = self$grid$x2, z = self$zmat) - private$.plot = plot_ly() %>% - add_trace( - name = self$plot_lab, - showlegend = FALSE, - showscale = FALSE, - x = llp$x, - y = llp$y, - z = t(llp$z), - type = "contour", - opacity = opacity, - colorscale = colorscale, - ... - ) %>% - layout( - title = if (show_title) self$plot_lab else NULL, - xaxis = list(title = self$x1_lab), - yaxis = list(title = self$x2_lab)) - - if (! private$.freeze_plot) { # Used in animate to not overwrite the - private$.opts = list() # plot over and over again when calling - private$.layer_arrow = list() # `$initLayerXXX`. - } - - return(invisible(self)) - }, - - #' @description - #' Initialize the plot as 3D surface. - #' - #' @param opacity (`numeric(1)`)\cr - #' Opacity of the layer. - #' @param colorscale (`list()`)\cr - #' The coloring of the surface. - #' @param show_title (`logical(1)`)\cr - #' Indicator whether to show the title of the plot. - #' @param show_contours (`logical(1)`)\cr - #' Indicator whether to show the contours of the surface. - #' @param ... (`any`)\cr - #' Further arguments passed to `add_trace(...)`. - init_layer_surface = function(opacity = 0.8, colorscale = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), show_contours = FALSE, show_title = TRUE, ...) { - assert_number(opacity, lower = 0, upper = 1) - assert_list(colorscale) - assert_flag(show_title) - - private$.vbase = c(as.list(environment()), list(...)) - private$.layer_primary = "surface" - - contours = if (show_contours) { - list( - z = list( - show = TRUE, - project = list(z = TRUE), - usecolormap = TRUE) - ) - } else NULL - - llp = list(x = self$grid$x1, y = self$grid$x2, z = self$zmat) - private$.plot = plot_ly() %>% - add_trace( - name = self$plot_lab, - showlegend = FALSE, - showscale = FALSE, - x = llp$x, - y = llp$y, - z = t(llp$z), - type = "surface", - opacity = opacity, - colorscale = colorscale, - contours = contours, - ... - ) %>% - layout( - title = if (show_title) self$plot_lab else NULL, - scene = list( - xaxis = list(title = self$x1_lab), - yaxis = list(title = self$x2_lab), - zaxis = list(title = self$z_lab) - ) - ) - - if (! private$.freeze_plot) { # Used in animate to not overwrite the plot over and over again. - private$.opts = list() - private$.layer_arrow = list() - } - - return(invisible(self)) - }, - - #' @description Set the layout of the plotly plot. - #' @param ... Layout options directly passed to `layout(...)`. - set_layout = function(...) { - private$.layout = list(...) - private$.plot = private$.plot %>% layout(...) - - return(invisible(self)) - }, - - #' @description Set the view for a 3D plot. - #' @param x (`numeric(1)`) The view from which the "camera looks down" to the plot. - #' @param y (`numeric(1)`) The view from which the "camera looks down" to the plot. - #' @param z (`numeric(1)`) The view from which the "camera looks down" to the plot. - set_scene = function(x, y, z) { - if (is.null(private$.plot)) self$init_layer_surface() - assert_number(x) - assert_number(y) - assert_number(z) - - if (private$.layer_primary != "surface") { - stop("Scene can only be set for `surface` plots") - } - - private$.plot = private$.plot %>% - layout(scene = list(camera = list(eye = list(x = x, y = y, z = z)))) - - return(invisible(self)) - }, - - #' @description Return the plot and hence plot it or do further processing. - plot = function() { - if (is.null(private$.plot)) self$init_layer_surface() - return(private$.plot) - }, - - - #' @description Save the plot by using plotlys `save_image()` function. - #' @param ... Further arguments passed to `save_image()`. - save = function(...) { - if (is.null(private$.plot)) self$init_layer_surface() - save_image(private$.plot, ...) - } - ), - private = list( - # @field .layer_primary (`character(1)`) The id of the primary layer. Used to determine - # the trace setup. - .layer_primary = NULL, - - # @field .layer_arrow (`list()`) Arguments passed to `$addLayerArrow()` to reconstruct the plot for animations. - .layer_arrow = list(), - - # @field .plot (`plot_ly()`) The plot. - .plot = NULL, - - # @field .opts (`list(Optimizer)`) List of optimizers used to add traces. Each `$initLayerXXX()` - # resets this list. An optimizer is added after each call to `$addLayerOptimizationTrace()`. - # this private field is exclusively used to create animations with `$animate()`. - .opts = list(), - - .vbase = list(), - - .layout = list(), - - # @field .freeze_plot (`logical(1)`) Indicator whether to freeze saving the plot elements. - .freeze_plot = FALSE, - - checkInit = function() { - if (is.null(private$.plot)) { - stop("Initialize plot with `initLayer*`") - } - return(invisible(TRUE)) - }, - checkInput = function(x) { - if (private$.layer_primary == "surface") { - return(checkmate::assertNumeric(x, len = 3L)) - } - if (private$.layer_primary == "contour") { - return(checkmate::assertNumeric(x, len = 3L)) - } - stop("Error in `$checkInput()`") - } - ) -) - -#' Randomly generate colors -#' @description Helper function to generate RGB colors. -#' @param alpha (`numeric(1)`) The alpha value. If `!is.null` the used prefix is 'rgba' instead of 'rgb'. -#' @return A character of length one containing the RGB color. -#' @import plotly -#' @import colorspace -#' @export -colSampler = function(alpha = NULL) { - checkmate::assertNumber(alpha, lower = 0, upper = 1, null.ok = TRUE) - r = sample(seq(0, 255), 1) - g = sample(seq(0, 255), 1) - b = sample(seq(0, 255), 1) - - if (is.null(alpha)) { - rgb = "rgb" - } else { - rgb = "rgba" - } - clr = sprintf("%s(%s)", rgb, paste(c(r, g, b, alpha), collapse = ", ")) - return(clr) -} diff --git a/R/Visualizer2DFun.R b/R/Visualizer2DFun.R new file mode 100644 index 0000000..3afec55 --- /dev/null +++ b/R/Visualizer2DFun.R @@ -0,0 +1,100 @@ +#FIXME: where is z_lab used? + + +#' @title Visualize Base Class +#' +#' @description +#' This class is used to create 2D visualizations. +#' +#' @template param_x1_limits +#' @template param_x2_limits +#' @template param_padding +#' @template param_n_points +#' +#' @export +Visualizer2DFun = R6::R6Class("Visualizer2DFun", + public = list( + + #' @field grid (`list()`)\cr + #' List with the `x1` and `x2` grid. + grid = NULL, + + #' @field zmat (`matrix()`)\cr + #' The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`. + zmat = NULL, + + #' @field title (character(1)\cr + #' Label of the plot. + title = NULL, + + #' @field lab_x1 (character(1)\cr + #' Label of the x1 axis. + lab_x1 = NULL, + + #' @field lab_x2 (character(1)\cr + #' Label of the x2 axis. + lab_x2 = NULL, + + #' @field z_lab (character(1)\cr + #' Label of the z axis. + z_lab = NULL, + + #' @description + #' Creates a new instance of this [R6][R6::R6Class] class. + #' + #' @param grid (`list()`)\cr + #' List with the `x1` and `x2` grid. + #' @param zmat (`matrix()`)\cr + #' The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`. + #' @param title (`character(1)`)\cr + #' Label of the plot. + #' @param lab_x1 (`character(1)`)\cr + #' Label of the x1 axis. + #' @param lab_x2 (`character(1)`)\cr + #' Label of the x2 axis. + #' @param z_lab (`character(1)`)\cr + #' Label of the z axis. + initialize = function(fun_x1, fun_x2, fun, title = NULL, lab_x1 = "x1", lab_x2 = "x2", z_lab = "z") { + self$fun_x1 = assert_numeric(fun_x1) + self$fun_x2 = assert_numeric(fun_x2) + self$fun = assert_function(fun) + self$title = assert_character(title, null.ok = TRUE) + self$lab_x1 = assert_character(lab_x1) + self$lab_x2 = assert_character(lab_x2) + self$z_lab = assert_character(z_lab) + self$fun_data = expand.grid(self$fun_1, self$fun_x2) + return(invisible(self)) + }, + + plot = function() { + pl = ggplot(data = self$fun_data, aes(x = x1, y = x2, z = y)) + pl = pl + geom_contour_filled(aes(fill = ..level..), show.legend = FALSE) + pl = pl + geom_contour(color = "white") + pl = pl + scale_fill_viridis_c() + pl = pl + labs(title = self$title, x = self$lab_x, y = self$lab_y) + } + ) +) + +#' Randomly generate colors +#' @description Helper function to generate RGB colors. +#' @param alpha (`numeric(1)`) The alpha value. If `!is.null` the used prefix is 'rgba' instead of 'rgb'. +#' @return A character of length one containing the RGB color. +#' @import plotly +#' @import colorspace +#' @export +colSampler = function(alpha = NULL) { +# FIXME: do we really need this? + checkmate::assertNumber(alpha, lower = 0, upper = 1, null.ok = TRUE) + r = sample(seq(0, 255), 1) + g = sample(seq(0, 255), 1) + b = sample(seq(0, 255), 1) + + if (is.null(alpha)) { + rgb = "rgb" + } else { + rgb = "rgba" + } + clr = sprintf("%s(%s)", rgb, paste(c(r, g, b, alpha), collapse = ", ")) + return(clr) +} diff --git a/R/Visualizer2DModel.R b/R/Visualizer2DModel.R index 1fe07f3..1c2ac4e 100644 --- a/R/Visualizer2DModel.R +++ b/R/Visualizer2DModel.R @@ -10,8 +10,7 @@ #' @template param_n_points #' #' @export -Visualizer2DModel = R6::R6Class("Visualizer2DModel", - inherit = Visualizer2D, +Visualizer2DModel = R6::R6Class("Visualizer2DModel", inherit = Visualizer2DFun, public = list( #' @field task (`mlr3::Task`)\cr diff --git a/R/Visualizer2DObjective.R b/R/Visualizer2DObj.R similarity index 99% rename from R/Visualizer2DObjective.R rename to R/Visualizer2DObj.R index 66b4c5d..3b1412a 100644 --- a/R/Visualizer2DObjective.R +++ b/R/Visualizer2DObj.R @@ -9,8 +9,7 @@ #' @template param_n_points #' #' @export -Visualizer2DObjective = R6::R6Class("Visualizer2DObjective", - inherit = Visualizer2D, +Visualizer2DObj = R6::R6Class("Visualizer2DObj", inherit = Visualizer2DFun, public = list( #' @field objective (`Objective`)\cr diff --git a/R/VisualizerLossFunction.R b/R/VisualizerLossFunction.R deleted file mode 100644 index 3087786..0000000 --- a/R/VisualizerLossFunction.R +++ /dev/null @@ -1,122 +0,0 @@ -#' @title Visualize Loss Function -#' -#' @description -#' This class is used to create visualizations of loss functions. -#' -#' @export -VisualizerLossFunction = R6::R6Class("VisualizerLossFunction", - public = list( - - #' @field loss_function [LossFunction]\cr - #' Loss function. - loss_function = NULL, - - #' @field loss (`numeric()`)\cr - #' Loss values. - loss = NULL, - - #' @field y_pred `numeric()`\cr - #' Predicted values. - y_pred = NULL, - - #' @description - #' Creates a new instance of this [R6][R6::R6Class] class. - #' - #' @param loss_function [LossFunction]\cr - #' Loss function. - #' @param y_pred (`numeric()`)\cr - #' Predicted values. - #' @param y_true (`numeric(1)`)\cr - #' True value. - #' @param ... (`any`)\cr - #' Additional arguments passed to the loss function. - initialize = function(loss_function, y_pred, y_true, ...) { - self$loss_function = assert_r6(loss_function, "LossFunction") - self$y_pred = assert_numeric(y_pred) - assert_number(y_true) - - self$loss = loss_function$fun(y_true, self$y_pred, ...) - }, - - #' @description - #' Initialize the plot with a line plot. - #' - #' @param width (`integer(1)`)\cr - #' Width of the line. - #' @param color (`character(1)`)\cr - #' Color of the line. - #' @param ... (`any`)\cr - #' Further arguments passed to `add_trace(...)`. - init_layer_lines = function(width = 2, color = "rgb(160,82,45)", ...) { - assert_int(width, lower = 1) - assert_character(color) - - llp = list(x = self$y_pred, y = self$loss) - private$.args = list( - name = self$loss_function$label, - showlegend = TRUE, - x = llp$x, - y = llp$y, - type = "scatter", - mode = "lines", - line = list(width = width, color = color), - ... - ) - - self$set_layout( - title = private$.title, - xaxis = list(title = if ("classif" %in% self$loss_function$properties) "Margin y * f(x)" else "Residual y - f(x)"), - yaxis = list(title = "Loss")) - - return(invisible(self)) - }, - - #' @description - #' Set the layout of the plotly plot. - #' - #' @param ... (`any`)\cr - #' Layout options directly passed to `layout(...)`. - set_layout = function(...) { - private$.layout = insert_named(private$.layout, list(...)) - - return(invisible(self)) - }, - - #' @description - #' Return the plot and hence plot it or do further processing. - plot = function() { - if (is.null(private$.args)) self$init_layer_lines() - plot = invoke(add_trace, plot_ly(), .args = private$.args) - invoke(layout, plot, .args = private$.layout) - }, - - #' @description - #' Save the plot by using plotlys `orca()` function. - #' - #' @param ... (`any`)\cr - #' Further arguments passed to `orca()`. - save = function(...) { - orca(self$plot, ...) - } - ), - - private = list( - .args = NULL, - .layout = NULL - ) -) - -#' @export -c.VisualizerLossFunction = function(...) { - visualizers = list(...) - walk(visualizers, function(visualizer) visualizer$init_layer_lines()) - title = str_collapse(map_chr(visualizers, function(visualizer) visualizer$loss_function$label), " & ") - - Reduce(function(x, y) { - invoke(add_trace, x, line = NULL, .args = get_private(y)$.args) - }, visualizers, plot_ly()) %>% - layout( - title = title, - xaxis = list(title = "Predictions"), - yaxis = list(title = "Loss")) -} diff --git a/R/VisualizerLossFuns.R b/R/VisualizerLossFuns.R new file mode 100644 index 0000000..a676e2e --- /dev/null +++ b/R/VisualizerLossFuns.R @@ -0,0 +1,79 @@ +#' @title Visualizer for Losses +#' +#' @description +#' Visualize one or multiple loss functions. +#' +#' @export +VisualizerLossFuns = R6::R6Class("VisualizerLossFuns", + public = list( + + #' @field loss_function [LossFunction]\cr + #' Loss function. + losses = NULL, + task_type = NULL, + lab_x = NULL, + lab_y = NULL, + title = NULL, + x_range = NULL, + line_width = NULL, + line_col = NULL, + line_type = NULL, + legend_title = element_blank(), + + # FIXME: better doc the class + + #' @description + #' Creates a new instance of this [R6][R6::R6Class] class. + #' + #' @param loss_function [LossFunction]\cr + #' Loss function. + initialize = function(losses) { + assert_list(losses, "LossFunction") + tts = unique(map_chr(losses, function(x) x$task_type)) + if (length(tts) > 1) + stopf("'LossFunction$task_type' all need to be the same, but found: %s", collapse(tts)) + ids = map_chr(losses, function(x) x$id) + names(losses) = ids + self$losses = losses + self$task_type = unique(tts) + self$title = "" + self$lab_x = ifelse(self$task_type == "classif", "y * f", "y - f") + self$lab_y = "Loss" + self$x_range = c(-5, 5) + n = length(losses) + self$line_width = rep(0.5, n) + self$line_col = NULL + self$line_type = rep("solid", n) + }, + + plot = function() { + # get lossfun labels so we can use them for legend + loss_labels = map_chr(self$losses, function(x) x$label) + # eval losses on defined range, then melt data into long format + r_seq = seq(self$x_range[1], self$x_range[2], by = 0.01) + loss_seqs = map_dtc(self$losses, function(ll) ll$fun(r_seq)) + dd = cbind(r = r_seq, loss_seqs) + dd = melt(dd, id.vars = "r", measure.vars = colnames(loss_seqs), + variable.name = "loss_fun", value.name = "loss_val") + # plot + pl = ggplot(data = dd, aes(x = r, y = loss_val, + col = loss_fun, linetype = loss_fun, size = loss_fun)) + pl = pl + geom_line() + # use cols, linetypes and widths + if (!is.null(self$line_col)) + pl = pl + scale_color_manual(values = self$line_col, labels = loss_labels) + else + pl = pl + scale_color_npg(labels = loss_labels) + if (!is.null(self$line_width)) + pl = pl + scale_size_manual(values = self$line_width, labels = loss_labels) + if (!is.null(self$line_type)) { + pl = pl + scale_linetype_manual(values = self$line_type, labels = loss_labels) + } + # use specified axis labels and legend title + pl = pl + labs(x = self$lab_x, y = self$lab_y) + pl = pl + theme(legend.title = self$legend_title) + return(pl) + } + ) +) + diff --git a/R/as_visualizer.R b/R/as_visualizer.R index 5b029d0..e69de29 100644 --- a/R/as_visualizer.R +++ b/R/as_visualizer.R @@ -1,59 +0,0 @@ -#' @title Convert to visualizer -#' -#' @description -#' This function converts to a visualizer. -#' -#' @param x (`any`)\cr -#' Object to convert to a visualizer. -#' @param ... (`any`)\cr -#' Additional arguments. -#' -#' @export -as_visualizer = function(x, ...) { - UseMethod("as_visualizer") -} - -#' @param learner (`mlr3::Learner`)\cr -#' The learner to train the model with. -#' @template param_x1_limits -#' @template param_x2_limits -#' @template param_padding -#' @template param_n_points -#' @rdname as_visualizer -#' @export -as_visualizer.Task = function(x, learner, x1_limits = NULL, x2_limits = NULL, padding = 0, n_points = 100L, ...) { - n_features = length(x$feature_names) - if (n_features == 1) { - Visualizer1DModel$new(x, learner, x1_limits = x1_limits, padding = padding, n_points = n_points, ...) - } else if (n_features == 2) { - Visualizer2DModel$new(x, learner, x1_limits = x1_limits, x2_limits = x2_limits, padding = padding, n_points = n_points, ...) - } else { - stop("Task has more than 2 features.") - } -} - -#' @rdname as_visualizer -#' @template param_x1_limits -#' @template param_x2_limits -#' @template param_padding -#' @template param_n_points -#' @export -as_visualizer.Objective = function(x, x1_limits = NULL, x2_limits = NULL, padding = 0, n_points = 100L, ...) { - if (x$xdim == 1) { - Visualizer1DObjective$new(x, x1_limits = x1_limits, padding = padding, n_points = n_points, ...) - } else if (x$xdim == 2) { - Visualizer2DObjective$new(x, x1_limits = x1_limits, x2_limits = x2_limits, padding = padding, n_points = n_points, ...) - } else { - stop("Objective has more than 2 dimensions.") - } -} - -#' @rdname as_visualizer -#' @param y_pred (`numeric()`)\cr -#' Predicted values. -#' @param y_true (`numeric(1)`)\cr -#' True value. -#' @export -as_visualizer.LossFunction = function(x, y_pred, y_true, ...) { - VisualizerLossFunction$new(x, y_pred, y_true, ...) -} diff --git a/test.R b/test.R new file mode 100644 index 0000000..81e0028 --- /dev/null +++ b/test.R @@ -0,0 +1,35 @@ + +library(devtools) +library(ggplot2) +library(ggsci) +load_all() + +# print(as.data.table(dict_loss)) +# lf1 = lss("hinge") +# lf2 = lss("cross-entropy") +# losses = list(lf1, lf2) +# vis = VisualizerLosses$new(losses) +# vis$line_type = c(hinge="solid", logloss="dashed") +# vis$line_col = c(hinge="pink", logloss="green") +# vis$line_width = c(hinge=9, logloss=2) +# print(vis) +# print(vis$plot()) + + +# task = tsk("boston_housing") +# task$select(c("age")) +# learner = lrn("regr.rpart") +# vis = Visualizer1DModel$new(task = task, learner = learner, plot_data = TRUE) +# vis$line_col = "red" +# vis$line_type = "dashed" +# vis$line_width = 5 +# pl = vis$plot() +# print(pl) + +# print(as.data.table(dict_objective)) +obj = obj("TF_branin") +# obj = Objective$new("f", fun = function(x) sum(x^2), xdim = 1, lower = -1, upper = 2) +vis = Visualizer2DObj$new(obj = obj) +pl = vis$plot() +print(pl) + From 206bf7de643b6c8f21e1cc8a953ae8b6188a70c9 Mon Sep 17 00:00:00 2001 From: be-marc Date: Fri, 25 Oct 2024 12:38:42 +0200 Subject: [PATCH 2/3] ... --- DESCRIPTION | 7 +- NAMESPACE | 12 +- R/{Visualizer1DFun.R => Visualizer1D.R} | 2 +- R/Visualizer1DModel.R | 2 +- R/Visualizer1DObj.R | 2 +- R/Visualizer2D.R | 88 ++++ R/Visualizer2DFun.R | 100 ----- R/Visualizer2DModel.R | 123 +++--- R/Visualizer2DObj.R | 397 +----------------- R/zzz.R | 1 + man/LossFunction.Rd | 16 +- man/Objective.Rd | 14 +- man/Visualizer1D.Rd | 160 +++---- man/Visualizer1DModel.Rd | 16 +- man/Visualizer1DObj.Rd | 94 +++++ man/Visualizer1DObjective.Rd | 109 ----- man/Visualizer2D.Rd | 159 +------ man/Visualizer2DModel.Rd | 7 +- ...lizer2DObjective.Rd => Visualizer2DObj.Rd} | 68 ++- man/VisualizerLossFunction.Rd | 152 ------- man/VisualizerLossFuns.Rd | 77 ++++ man/as_visualizer.Rd | 65 --- man/mlr_learners_regr.lm_formula.Rd | 2 +- tests/testthat.R | 12 + tests/testthat/test-Visualizer2DModel.R | 39 ++ tests/testthat/test-Visualizer2DObj.R | 9 + 26 files changed, 558 insertions(+), 1175 deletions(-) rename R/{Visualizer1DFun.R => Visualizer1D.R} (98%) create mode 100644 R/Visualizer2D.R delete mode 100644 R/Visualizer2DFun.R create mode 100644 man/Visualizer1DObj.Rd delete mode 100644 man/Visualizer1DObjective.Rd rename man/{Visualizer2DObjective.Rd => Visualizer2DObj.Rd} (66%) delete mode 100644 man/VisualizerLossFunction.Rd create mode 100644 man/VisualizerLossFuns.Rd delete mode 100644 man/as_visualizer.Rd create mode 100644 tests/testthat.R create mode 100644 tests/testthat/test-Visualizer2DModel.R create mode 100644 tests/testthat/test-Visualizer2DObj.R diff --git a/DESCRIPTION b/DESCRIPTION index 1db542c..537a503 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -19,6 +19,7 @@ Imports: checkmate, colorspace, data.table, + ggplot2, mlr3, mlr3misc, paradox, @@ -34,8 +35,10 @@ Suggests: mlr3learners, mlr3pipelines, patchwork, - rmarkdown + rmarkdown, + testthat (>= 3.0.0) VignetteBuilder: knitr Encoding: UTF-8 -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 +Config/testthat/edition: 3 diff --git a/NAMESPACE b/NAMESPACE index f47f560..28ff780 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,10 +2,6 @@ S3method(as.data.table,DictionaryLoss) S3method(as.data.table,DictionaryObjective) -S3method(as_visualizer,LossFunction) -S3method(as_visualizer,Objective) -S3method(as_visualizer,Task) -S3method(c,VisualizerLossFunction) export(LearnerRegrLMFormula) export(LossFunction) export(Objective) @@ -15,13 +11,12 @@ export(OptimizerMomentum) export(OptimizerNAG) export(Visualizer1D) export(Visualizer1DModel) -export(Visualizer1DObjective) +export(Visualizer1DObj) export(Visualizer2D) export(Visualizer2DModel) -export(Visualizer2DObjective) -export(VisualizerLossFunction) +export(Visualizer2DObj) +export(VisualizerLossFuns) export(as.data.table) -export(as_visualizer) export(assertStepSizeControl) export(colSampler) export(data.table) @@ -39,6 +34,7 @@ import(TestFunctions) import(checkmate) import(colorspace) import(data.table) +import(ggplot2) import(mlr3) import(mlr3misc) import(paradox) diff --git a/R/Visualizer1DFun.R b/R/Visualizer1D.R similarity index 98% rename from R/Visualizer1DFun.R rename to R/Visualizer1D.R index 8a04b9c..5fb4a50 100644 --- a/R/Visualizer1DFun.R +++ b/R/Visualizer1D.R @@ -9,7 +9,7 @@ #' @template param_n_points #' #' @export -Visualizer1DFun = R6::R6Class("Visualizer1DFun", +Visualizer1D = R6::R6Class("Visualizer1D", public = list( #' @field x (`numeric(n)`)\cr diff --git a/R/Visualizer1DModel.R b/R/Visualizer1DModel.R index 0c4a0fd..d1b6e11 100644 --- a/R/Visualizer1DModel.R +++ b/R/Visualizer1DModel.R @@ -9,7 +9,7 @@ #' @template param_n_points #' #' @export -Visualizer1DModel = R6::R6Class("Visualizer1DModel", inherit = Visualizer1DFun, +Visualizer1DModel = R6::R6Class("Visualizer1DModel", inherit = Visualizer1D, public = list( #' @field task (`mlr3::Task`)\cr diff --git a/R/Visualizer1DObj.R b/R/Visualizer1DObj.R index 13a38b1..a338fc3 100644 --- a/R/Visualizer1DObj.R +++ b/R/Visualizer1DObj.R @@ -12,7 +12,7 @@ #' @template param_n_points #' #' @export -Visualizer1DObj = R6::R6Class("Visualizer1DObj", inherit = Visualizer1DFun, +Visualizer1DObj = R6::R6Class("Visualizer1DObj", inherit = Visualizer1D, public = list( #' @field objective (`Objective`)\cr diff --git a/R/Visualizer2D.R b/R/Visualizer2D.R new file mode 100644 index 0000000..da6501d --- /dev/null +++ b/R/Visualizer2D.R @@ -0,0 +1,88 @@ +#' @title Visualize Base Class +#' +#' @description +#' This class is used to create 2D visualizations. +#' +#' @template param_x1_limits +#' @template param_x2_limits +#' @template param_padding +#' @template param_n_points +#' +#' @export +Visualizer2D = R6::R6Class("Visualizer2D", + public = list( + + #' @field fun_x1 (`numeric(n)`) + fun_x1 = NULL, + + #' @field fun_x2 (`numeric(n)`) + fun_x2 = NULL, + + #' @field fun_y (`numeric(n)`) + fun_y = NULL, + + #' @field title (`character(1)`) + title = NULL, + + #' @field lab_x1 (`character(1)`) + lab_x1 = NULL, + + #' @field lab_x2 (`character(1)`) + lab_x2 = NULL, + + #' @field lab_y (`character(1)`) + lab_y = NULL, + + #' @field points_x1 (`numeric()`)\cr + points_x1 = NULL, + + #' @field points_x2 (`numeric()`)\cr + points_x2 = NULL, + + points_y = NULL, + + #' @description + #' Creates a new instance of this [R6][R6::R6Class] class. + #' + #' @param fun_x1 (`numeric()`) + #' x-values of function. + #' @param fun_x2 (`numeric()`) + #' x-values of function. + #' @param fun_y (`numeric()`) + #' y-values of function. + #' @param title (`character(1)`) + #' Title of plot. + #' @param lab_x1 (`character(1)`) + #' Label of x-axis. + #' @param lab_x2 (`character(1)`) + #' Label of x-axis. + #' @param lab_y (`character(1)`) + #' Label of y-axis. + initialize = function(fun_x1, fun_x2, fun_y, title = NULL, lab_x1 = "x1", lab_x2 = "x2", lab_y = "y") { + self$fun_x1 = assert_numeric(fun_x1) + self$fun_x2 = assert_numeric(fun_x2) + self$fun_y = assert_numeric(fun_y) + self$title = assert_character(title, null.ok = TRUE) + self$lab_x1 = assert_character(lab_x1) + self$lab_x2 = assert_character(lab_x2) + self$lab_y = assert_character(lab_y) + }, + + plot = function() { + data = data.table(fun_x1 = self$fun_x1, fun_x2 = self$fun_x2, fun_y = self$fun_y) + + p = ggplot(data, aes(x = fun_x1, y = fun_x2, z = fun_y)) + + geom_contour_filled() + + geom_contour(color = "white") + + labs(title = self$title, x = self$lab_x1, y = self$lab_x2) + + if (!is.null(self$points_x1)) { + data = data.table(points_x1 = self$points_x1, points_x2 = self$points_x2, points_y = self$points_y) + p = p + geom_point(data = data, aes(x = points_x1, y = points_x2, color = self$points_y), size = 5) + } + + return(p) + } + ) +) + diff --git a/R/Visualizer2DFun.R b/R/Visualizer2DFun.R deleted file mode 100644 index 3afec55..0000000 --- a/R/Visualizer2DFun.R +++ /dev/null @@ -1,100 +0,0 @@ -#FIXME: where is z_lab used? - - -#' @title Visualize Base Class -#' -#' @description -#' This class is used to create 2D visualizations. -#' -#' @template param_x1_limits -#' @template param_x2_limits -#' @template param_padding -#' @template param_n_points -#' -#' @export -Visualizer2DFun = R6::R6Class("Visualizer2DFun", - public = list( - - #' @field grid (`list()`)\cr - #' List with the `x1` and `x2` grid. - grid = NULL, - - #' @field zmat (`matrix()`)\cr - #' The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`. - zmat = NULL, - - #' @field title (character(1)\cr - #' Label of the plot. - title = NULL, - - #' @field lab_x1 (character(1)\cr - #' Label of the x1 axis. - lab_x1 = NULL, - - #' @field lab_x2 (character(1)\cr - #' Label of the x2 axis. - lab_x2 = NULL, - - #' @field z_lab (character(1)\cr - #' Label of the z axis. - z_lab = NULL, - - #' @description - #' Creates a new instance of this [R6][R6::R6Class] class. - #' - #' @param grid (`list()`)\cr - #' List with the `x1` and `x2` grid. - #' @param zmat (`matrix()`)\cr - #' The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`. - #' @param title (`character(1)`)\cr - #' Label of the plot. - #' @param lab_x1 (`character(1)`)\cr - #' Label of the x1 axis. - #' @param lab_x2 (`character(1)`)\cr - #' Label of the x2 axis. - #' @param z_lab (`character(1)`)\cr - #' Label of the z axis. - initialize = function(fun_x1, fun_x2, fun, title = NULL, lab_x1 = "x1", lab_x2 = "x2", z_lab = "z") { - self$fun_x1 = assert_numeric(fun_x1) - self$fun_x2 = assert_numeric(fun_x2) - self$fun = assert_function(fun) - self$title = assert_character(title, null.ok = TRUE) - self$lab_x1 = assert_character(lab_x1) - self$lab_x2 = assert_character(lab_x2) - self$z_lab = assert_character(z_lab) - self$fun_data = expand.grid(self$fun_1, self$fun_x2) - return(invisible(self)) - }, - - plot = function() { - pl = ggplot(data = self$fun_data, aes(x = x1, y = x2, z = y)) - pl = pl + geom_contour_filled(aes(fill = ..level..), show.legend = FALSE) - pl = pl + geom_contour(color = "white") - pl = pl + scale_fill_viridis_c() - pl = pl + labs(title = self$title, x = self$lab_x, y = self$lab_y) - } - ) -) - -#' Randomly generate colors -#' @description Helper function to generate RGB colors. -#' @param alpha (`numeric(1)`) The alpha value. If `!is.null` the used prefix is 'rgba' instead of 'rgb'. -#' @return A character of length one containing the RGB color. -#' @import plotly -#' @import colorspace -#' @export -colSampler = function(alpha = NULL) { -# FIXME: do we really need this? - checkmate::assertNumber(alpha, lower = 0, upper = 1, null.ok = TRUE) - r = sample(seq(0, 255), 1) - g = sample(seq(0, 255), 1) - b = sample(seq(0, 255), 1) - - if (is.null(alpha)) { - rgb = "rgb" - } else { - rgb = "rgba" - } - clr = sprintf("%s(%s)", rgb, paste(c(r, g, b, alpha), collapse = ", ")) - return(clr) -} diff --git a/R/Visualizer2DModel.R b/R/Visualizer2DModel.R index 1c2ac4e..3da7502 100644 --- a/R/Visualizer2DModel.R +++ b/R/Visualizer2DModel.R @@ -10,7 +10,8 @@ #' @template param_n_points #' #' @export -Visualizer2DModel = R6::R6Class("Visualizer2DModel", inherit = Visualizer2DFun, +Visualizer2DModel = R6::R6Class("Visualizer2DModel", + inherit = Visualizer2D, public = list( #' @field task (`mlr3::Task`)\cr @@ -28,94 +29,74 @@ Visualizer2DModel = R6::R6Class("Visualizer2DModel", inherit = Visualizer2DFun, #' The task to train the model on. #' @param learner ([mlr3::Learner])\cr #' The learner to train the model with. - initialize = function(task, learner, x1_limits = NULL, x2_limits = NULL, padding = 0, n_points = 100L) { + initialize = function( + task, + learner, + x1_limits = NULL, + x2_limits = NULL, + padding = 0, + n_points = 100L + training_data = FALSE + ) { + self$task = assert_task(task) self$learner = assert_learner(learner, task = self$task) assert_numeric(x1_limits, len = 2, null.ok = TRUE) assert_numeric(x2_limits, len = 2, null.ok = TRUE) assert_count(n_points) - x1 = self$task$feature_names[1] - x2 = self$task$feature_names[2] + lab_x1 = self$task$feature_names[1] + lab_x2 = self$task$feature_names[2] data = task$data() self$learner$train(task) - x1_limits = range(data[, x1, with = FALSE]) - x2_limits = range(data[, x2, with = FALSE]) + x1_limits = range(data[, lab_x1, with = FALSE]) + x2_limits = range(data[, lab_x2, with = FALSE]) - grid = list( - x1 = seq(x1_limits[1] - padding, x1_limits[2] + padding, length.out = n_points), - x2 = seq(x2_limits[1] - padding, x2_limits[2] + padding, length.out = n_points) - ) + x1 = seq(x1_limits[1] - padding, x1_limits[2] + padding, length.out = n_points) + x2 = seq(x2_limits[1] - padding, x2_limits[2] + padding, length.out = n_points) - newdata = set_names(CJ(grid$x1, grid$x2), self$task$feature_names) - z = self$learner$predict_newdata(newdata)[[self$learner$predict_type]] - if (self$learner$predict_type == "prob") z = z[, "pos"] - zmat = matrix(z, nrow = n_points, ncol = n_points, byrow = FALSE) + newdata = set_names(CJ(x1, x2), self$task$feature_names) + y = self$learner$predict_newdata(newdata)[[self$learner$predict_type]] + if (self$learner$predict_type == "prob") y = y[, task$positive] super$initialize( - grid = grid, - zmat = zmat, - plot_lab = sprintf("%s on %s", self$learner$id, self$task$id), - x1_lab = x1, - x2_lab = x2, - z_lab = task$target_names + fun_x1 = newdata[, lab_x1, with = FALSE][[1]], + fun_x2 = newdata[, lab_x2, with = FALSE][[1]], + fun_y = y, + title = sprintf("%s on %s", self$learner$id, self$task$id), + lab_x1 = lab_x1, + lab_x2 = lab_x2, + lab_y = task$target_names ) - return(invisible(self)) - }, - - #' @description - #' Adds the training data to the plot. - #' - #' @param size (`numeric(1)`)\cr - #' Size of the points. - #' @param color (`character(1)`)\cr - #' Color of the points. - #' @param ... (`any`)\cr - #' Further arguments passed to `add_trace(...)`. - add_training_data = function(size = 5, color = "grey",...) { - if (is.null(private$.plot)) self$init_layer_surface() - data = self$task$data() - x1 = data[, self$task$feature_names[1], with = FALSE][[1]] - x2 = data[, self$task$feature_names[2], with = FALSE][[1]] - z = data[, self$task$target_names, with = FALSE][[1]] - if (self$learner$predict_type == "prob") z = as.integer(z) - 1 - - private$.plot = private$.plot %>% - add_trace( - x = x1, - y = x2, - z = z, - type = "scatter3d", - mode = "markers", - marker = list(size = 5, color = grey), - ... - ) + if (training_data) { - return(invisible(self)) + } }, - #' @description - #' Adds the decision boundary to the plot. - #' - #' @param threshold (`numeric(1)`)\cr - #' Threshold for the decision boundary. - #' @param surfacecolor (`list()`)\cr - #' The coloring of the surface. - #' @param ... (`any`)\cr - #' Further arguments passed to `add_trace(...)`. - add_decision_boundary = function(threshold = 0.5, surfacecolor = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), ...) { - if (is.null(private$.plot)) self$init_layer_surface() - z = matrix(threshold, nrow = nrow(self$zmat), ncol = ncol(self$zmat), byrow = TRUE) + plot = function() { + if (training_data) { + data = task$data() + self$points_x1 = data[[lab_x1]] + self$points_x2 = data[[lab_x2]] + self$points_y = data[[task$target_names]] + } + - private$.plot = private$.plot %>% - add_surface( - x = self$grid$x1, - y = self$grid$x2, - z = z, - colorscale = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), - showscale = FALSE, - ...) + if (training_data) { + data = task$data() + # if (self$learner$predict_type == "prob") points_y = as.integer(points_y) - 1 + browser() + super$plot() + + geom_point(aes( + x = .data[[self$task$feature_names[1]]], + y = .data[[self$task$feature_names[2]]], + color = .data[[self$task$target_names]]), + data = data, size = 5, inherit.aes = FALSE) + + scale_color_viridis_c() + } else { + super$plot() + } } ) ) diff --git a/R/Visualizer2DObj.R b/R/Visualizer2DObj.R index 3b1412a..dca93eb 100644 --- a/R/Visualizer2DObj.R +++ b/R/Visualizer2DObj.R @@ -9,7 +9,8 @@ #' @template param_n_points #' #' @export -Visualizer2DObj = R6::R6Class("Visualizer2DObj", inherit = Visualizer2DFun, +Visualizer2DObj = R6::R6Class("Visualizer2DObj", + inherit = Visualizer2D, public = list( #' @field objective (`Objective`)\cr @@ -23,7 +24,13 @@ Visualizer2DObj = R6::R6Class("Visualizer2DObj", inherit = Visualizer2DFun, #' @param objective (`Objective`)\cr #' The objective which was optimized. #' This object is used to generate the surface/contour lines. - initialize = function(objective, x1_limits = NULL, x2_limits = NULL, padding = 0, n_points = 100L) { + initialize = function( + objective, + x1_limits = NULL, + x2_limits = NULL, + padding = 0, + n_points = 100L + ) { self$objective = assert_r6(objective, "Objective") assert_numeric(x1_limits, len = 2, null.ok = TRUE) assert_numeric(x2_limits, len = 2, null.ok = TRUE) @@ -34,8 +41,8 @@ Visualizer2DObj = R6::R6Class("Visualizer2DObj", inherit = Visualizer2DFun, stopf("`Visualizer2D` requires 2-dimensional inputs, but `objective$xdim = %s`", objective$xdim) } - x1_limits = x1_limits %??% c(objective$limits_lower[1], objective$limits_upper[1]) - x2_limits = x2_limits %??% c(objective$limits_lower[2], objective$limits_upper[2]) + x1_limits = x1_limits %??% c(objective$lower[1], objective$upper[1]) + x2_limits = x2_limits %??% c(objective$lower[2], objective$upper[2]) if (any(is.na(x1_limits)) || any(is.na(x2_limits))) { stop("Limits could not be extracted from the objective. Please use `x_limits`.") @@ -44,381 +51,23 @@ Visualizer2DObj = R6::R6Class("Visualizer2DObj", inherit = Visualizer2DFun, x1_pad = (x1_limits[2] - x1_limits[1]) * padding x2_pad = (x2_limits[2] - x2_limits[1]) * padding - grid = list( - x1 = unique(seq(x1_limits[1] - x1_pad, x1_limits[2] + x1_pad, length.out = n_points)), - x2 = unique(seq(x2_limits[1] - x2_pad, x2_limits[2] + x2_pad, length.out = n_points))) + x1 = unique(seq(x1_limits[1] - x1_pad, x1_limits[2] + x1_pad, length.out = n_points)) + x2 = unique(seq(x2_limits[1] - x2_pad, x2_limits[2] + x2_pad, length.out = n_points)) + grid = CJ(x1, x2) - zmat = outer(grid$x1, grid$x2, function(x, y) { - xin = cbind(x, y) - apply(xin, 1, function(x) self$objective$eval(x)) + y = pmap_dbl(grid, function(x1, x2) { + self$objective$eval(c(x1, x2)) }) super$initialize( - grid = grid, - zmat = zmat, - plot_lab = self$objective$label, - x1_lab = "x1", - x2_lab = "x2", - z_lab = "y" + fun_x1 = grid[, "x1", with = FALSE][[1]], + fun_x2 = grid[, "x2", with = FALSE][[1]], + fun_y = y, + title = self$objective$label, + lab_x1 = "x1", + lab_x2 = "x2", + lab_y = "y" ) - - return(invisible(self)) - }, - - #' @description - #' Add an optimization trace. - #' - #' @param opt (`Optimizer`)\cr - #' The optimizer from which the archive is extracted and used to plot the trace. - #' @param line_color (`character(1)`)\cr - #' The color of the trace. - #' @param mcolor_out (`character(1)`)\cr - #' The outer line color of the marker. - #' @param npoints (`integer(1)`)\cr - #' The number of used points from the archive. - #' Default is `NULL` which means that all points are used. - #' If set, a sequence from 1 to `nrow(opt$archive)` is created. - #' @param npmax (`integer(1)`)\cr - #' The number of points used from the sequence `seq_len(nrow(opt$archive))[seq_len(npmax)]` - #' @param name (`character(1)`)\cr - #' The name of the trace in the legend. - #' Default is `NULL` which means that the name is pasted from `opt$id` and `objective$id`. - #' @param offset (`numeric(3)`)\cr - #' Trace shift in direction (x, y, z). - #' @param add_marker_at (`integer()`)\cr - #' Vector of iterations at which a marker is added. - #' @param marker_shape (`character()`)\cr - #' Vector indicating the shape of the markers. - #' If `length(marker_shape) == 1`, all markers get the same shape. - #' The other option is to specify all markers individually by passing a vector of `length(add_marker_at)`. - #' For a list of all shapes see `schema(F)$traces$XXX$attributes$marker$symbol$values` with `XXX` one of `scatter` or `scatter3d`. - #' If `marker_shape = NA`, no marker are added. - #' @param marker_color (`character()`)\cr - #' The colors for the markers. - #' @param ... Further arguments passed to `add_trace(...)`. - add_optimization_trace = function(opt, line_color = colSampler(), mcolor_out = "black", npoints = NULL, npmax = NULL, name = NULL, offset = NULL, add_marker_at = 1, marker_shape = "circle", marker_color = NULL, ...) { - assert_r6(opt, "Optimizer") - assert_count(npoints, null.ok = TRUE) - assert_count(npmax, null.ok = TRUE) - assert_string(line_color) - if (is.null(private$.plot)) self$init_layer_surface() - - if (nrow(opt$archive) == 0) { - stop("No optimization trace in `opt$archive`. Did you forget to call `opt$optimize(steps)`?") - } - - if (private$.layer_primary == "contour") { - checkmate::assertNumeric(offset, len = 2L, null.ok = TRUE) - if (is.null(offset)) { - offset = rep(0, 2) - } - offset[3] = 0 - } - if (private$.layer_primary == "surface") { - checkmate::assertNumeric(offset, len = 3L, null.ok = TRUE) - if (is.null(offset)) { - offset = rep(0, 3) - } - } - - # Catch additional arguments: - aargs = list(...) - - if (! private$.freeze_plot) { # Just set by animate to not save the optimizer over and over again for each frame. - private$.opts = c(private$.opts, list(c(as.list(environment()), aargs))) - } - - # Assert marker styling: - checkmate::assertIntegerish(add_marker_at, lower = 1, upper = nrow(opt$archive)) - if (is.null(marker_shape)) marker_shape = NA - if (length(marker_shape) == 1) marker_shape = rep(marker_shape, length(add_marker_at)) - mvals = NULL - if (private$.layer_primary == "contour") { - mvals = schema(F)$traces$scatter$attributes$marker$symbol$values - } - if (private$.layer_primary == "surface") { - mvals = schema(F)$traces$scatter3d$attributes$marker$symbol$values - } - invisible(lapply(marker_shape, function(marker_shape) checkmate::assertChoice(marker_shape, choices = c(mvals, NA)))) - - if (is.null(marker_color)) marker_color = line_color - if (length(marker_color) == 1) { - marker_color = rep(marker_color, length(marker_shape)) - } - checkmate::assertCharacter(marker_color, len = length(marker_shape), null.ok = TRUE) - - # Define marker coordinates for plotting: - xmat = do.call(rbind, c(opt$archive$x_in[1], opt$archive$x_out)) - xmarkers = data.frame(x = xmat[, 1] + offset[1], y = xmat[, 2] + offset[2], - z = c(opt$archive$fval_in[1], opt$archive$fval_out) + offset[3]) - if (is.null(npoints)) { - npoints = nrow(xmarkers) - } - if (is.null(npmax)) { - npmax = nrow(xmarkers) - if (npmax > nrow(xmarkers)) { - npmax = nrow(xmarkers) - } - } - # Cut marker after npmax iterations (if specified): - xmr = xmarkers[unique(round(seq(1, nrow(xmarkers), length.out = npoints))), ] - xmr = xmr[seq_len(npmax), ] - add_marker_at = add_marker_at[add_marker_at <= npmax] - - ptype = NULL - if (is.null(name)) { - name = paste0(opt$id, " on ", opt$objective$id) - } - - # Define the plotting arguments as list, so we can call `do.call` with these arguments. This is - # more comfortable due to just one call to `add_trace`. Additionally, it is easier to control - # different default stylings (such as line width) and to recreate the layer with the stored arguments: - if (private$.layer_primary == "surface") { - ptype = "scatter3d" - pargs = list( - name = name, - x = xmr$x, - y = xmr$y, - z = xmr$z, - marker = list(color = line_color, line = list(color = mcolor_out, width = 6)), - line = list(color = line_color, width = 8)) - } - if (private$.layer_primary == "contour") { - ptype = "scatter" - pargs = list( - name = name, - x = xmr$x, - y = xmr$y, - marker = list(color = line_color, size = 12, line = list(color = mcolor_out, width = 2)), - line = list(color = line_color, width = 2)) - } - if (is.null(ptype)) { - stop("No known plot mode") - } - pargs$type = ptype - - # Add optimization traces as lines to the plot: - private$.plot = do.call(add_trace, c(list(private$.plot), - mlr3misc::insert_named(mlr3misc::remove_named(pargs, "marker"), aargs), - list(mode = "lines"))) - - # Now add marker to the lines. Marker are added at `add_marker_at` iterations - # and with the specified shape and color: - pargs = list( - x = xmarkers$x[add_marker_at], - y = xmarkers$y[add_marker_at], - z = xmarkers$z[add_marker_at], - mode = "markers", - type = ptype, - marker = insert_named(pargs$marker, list(symbol = marker_shape, color = marker_color)), - showlegend = FALSE) - if (private$.layer_primary == "contour") { - pargs$z = NULL - } - private$.plot = do.call(add_trace, c(list(private$.plot), pargs)) - - return(invisible(self)) - }, - - #' @description - #' Add a Taylor approximation (for 1 and 2 degrees). - #' - #' @param x0 (`numeric()) `\cr - #' The point around which the approximation is done. - #' @param degree (`integer(1)`)\cr - #' The degree of the approximation (only 1 and 2 is implemented). - #' @param x1margin (`numeric(1)`)\cr - #' The "length" of the hyperplane in direction x1. - #' @param x2margin (`numeric(1)`)\cr - #' The "length" of the hyperplane in direction x2. - #' @param npoints_per_dim (`integer(1)`)\cr - #' Number of points per dimension for the plotting grid. - #' @param zlim (`numeric(2)`)\cr - #' The limits for z. - #' Can be helpful if the hyperplane as a huge z range and therefore the plot looks ugly. - #' @param ... (`any`)\cr - #' Additional parameter passed to `add_surface()`. - add_layer_taylor = function(x0, degree = 2, x1margin = 0, x2margin = 0, npoints_per_dim = 20L, zlim = NULL, ...) { - private$checkInit() - if (private$.layer_primary != "surface") stop("Atm just available for `surface`") - checkmate::assertNumeric(x0, len = 2L) - checkmate::assertIntegerish(degree, len = 1, lower = 1, upper = 2) - checkmate::assertNumber(x1margin) - checkmate::assertNumber(x2margin) - - #checkmate::assertNumeric(x1limits, len = 2L, null.ok = TRUE) - #checkmate::assertNumeric(x2limits, len = 2L, null.ok = TRUE) - - #if (is.null(x1limits)) x1limits = x0[1] + c(-0.05, 0.05) - #if (is.null(x2limits)) x2limits = x0[2] + c(-0.05, 0.05) - - f0 = self$objective$eval(x0) - g = self$objective$grad(x0) - h = self$objective$hess(x0) - - # Create box based on the gradient at x0: - # - Normalize vector to length x1margin / 2 - # - Calculate perpendicular vector - # - These vectors define the rotation - gn = g / l2norm(g) - gp = rbind(c(0, -1), c(1, 0)) %*% gn - - gn = gn * x1margin / 2 - gp = gp * x2margin / 2 - - # - Create grid in (0,0) x (1,1) and rotate w.r.t. to gn and gp: - rotation = cbind(gn, gp) - square = as.matrix(expand.grid(x = seq(0, 1, len = npoints_per_dim), y = seq(0, 1, len = npoints_per_dim))) - grid = square %*% rotation - grid[, 1] = grid[, 1] - max(grid[, 1]) + (max(grid[, 1]) - min(grid[, 1])) / 2 + x0[1] - grid[, 2] = grid[, 2] - max(grid[, 2]) + (max(grid[, 2]) - min(grid[, 2])) / 2 + x0[2] - - fapp = function(x) { - out = f0 + crossprod(g, x - x0) * f0 - if (degree == 2) { - out = out + 0.5 * f0 * t(x - x0) %*% h %*% (x - x0) - } - return(as.numeric(out)) - } - fappV = function(x, y) { - X = cbind(x = x, y = y) - apply(X, 1, fapp) - } - z = outer(X = grid[,1], Y = grid[,2], FUN = function(x, y) fappV(x, y)) - if (! is.null(zlim)) { - checkmate::assertNumeric(zlim, len = 2L) - z[! between(z, zlim[1], zlim[2])] = NA - } - - private$.plot = private$.plot %>% add_surface(x = grid[, 1], y = grid[, 2], z = t(z), showscale = FALSE, ...) - }, - - #' @description - #' Add two "arrows" as eigenvectors of the Hessian. - #' - #' @param x0 (`numeric(2)`)\cr - #' The point at which the Hessian is calculated. - #' @param x1length (`numeric(1)`)\cr - #' The length of the first eigenvector. - #' @param x2length (`numeric(1)`)\cr - #' The length of the second eigenvector. - #' @param ... (`any`)\cr - #' Additional arguments passed to `add_trace`. - add_layer_hessian = function(x0, x1length = 0.1, x2length = 0.1, ...) { - private$checkInit() - checkmate::assertNumeric(x0, len = 2L) - checkmate::assertNumber(x1length) - checkmate::assertNumber(x2length) - - f0 = self$objective$eval(x0) - h = self$objective$hess(x0) - ev = eigen(h)$vectors - - v1 = ev[, 1] - v2 = ev[, 2] - - if (private$.layer_primary == "contour") { - # Transpose x and y to macht contour: - v1 = v1 * x1length + x0 - v2 = v2 * x2length + x0 - - mx = c(v1[1], x0[1], v2[1]) - my = c(v1[2], x0[2], v2[2]) - - private$.plot = private$.plot %>% add_trace(x = mx, y = my, mode = "lines", type = "scatter", showlegend = FALSE, ...) - } - if (private$.layer_primary == "surface") { - v1 = v1 * x1length + x0 - v2 = v2 * x2length + x0 - - v0 = c(x0, f0) - v1 = c(v1, f0) - v2 = c(v2, f0) - - # Order is important to have the angle: - marker = cbind(v1, v0, v2) - - private$.plot = private$.plot %>% add_trace(x = marker[1, ], y = marker[2, ], z = marker[3, ], mode = "lines", type = "scatter3d", showlegend = FALSE, ...) - } - }, - - #' @description - #' Create an animation of `$plot()`. - #' - #' @param dir (`character(1)`)\cr - #' The directory in which all the images are saved. - #' @param nframes (`integer(1)`)\cr - #' The number of frames. - #' @param view_start (`list()`)\cr - #' The start view of the animation. - #' @param view_end (`list()`)\cr - #' The end view of the animation. - #' @param fext (`character(1)`)\cr - #' The file extension (default is `png`). - #' @param stops (`integer()`)\cr - #' The step / iteration in the archives of the optimizers added by `$addLayerOptimizationTrace()` at which a frame is taken. - #' Must have exact the same length as defined in `nframes`. - #' By default, a sequence with equidistant points is generated for `stops`. - #' @param ... (`any`)\cr - #' Additional arguments passed to `$save(...)`. - animate = function(dir = "animation", nframes = 10L, view_start = list(x = 1, y = 1, z = 1), - view_end = list(x = 1, y = 1, z = 1), fext = "png", stops = NULL, ...) { - - checkmate::assertDirectory(dir) - checkmate::assertCount(nframes) - checkmate::assertList(view_start) - checkmate::assertList(view_end) - checkmate::assertIntegerish(stops, lower = 1, len = nframes, null.ok = TRUE) - - if (! all((names(view_start) == c("x", "y", "z")) | (names(view_end) == c("x", "y", "z")))) { - stop("View needs `x`, `y`, and `z` coordinates.") - } - invisible(lapply(c(view_start, view_end), checkmate::assertNumber)) - - views = list( - x = seq(view_start$x, view_end$x, len = nframes), - y = seq(view_start$y, view_end$y, len = nframes), - z = seq(view_start$z, view_end$z, len = nframes)) - - if (is.null(stops)) { - maxcalls = max(vapply(private$.opts, function(oo) nrow(oo$opt$archive), integer(1))) - stops = unique(round(seq(1, maxcalls, len = nframes))) - } - - plot_temp = private$.plot - private$.freeze_plot = TRUE - - for (i in seq_len(nframes)) { - - is = stringr::str_pad(i, width = 4, pad = "0") - fname = sprintf("%s/frame-%s.%s", dir, is, fext) - - if (private$.layer_primary == "surface") { - do.call(self$initLayerSurface, private$.vbase) - } - if (private$.layer_primary == "contour") { - do.call(self$initLayerContour, private$.vbase) - } - if (is.null(private$.layer_primary)) { - stop("No figure was created jet") - } - - for (j in seq_along(private$.opts)) { - do.call(self$addLayerOptimizationTrace, mlr3misc::insert_named(private$.opts[[j]], list(npmax = stops[i]))) - } - - if (private$.layer_primary == "surface") { - self$setScene(x = views$x[i], y = views$y[i], z = views$z[i]) - } - do.call(self$setLayout, private$.layout) - - self$save(fname, ...) - } - - private$.freeze_plot = FALSE - private$.plot = plot_temp - - message(sprintf("Files stored in '%s'. Use, e.g., ImageMagic (http://www.imagemagick.org/) with `convert -delay 20 -loop 0 %s/*.%s myimage.gif` to create gif with 20 ms frames.", dir, dir, fext)) } ) ) diff --git a/R/zzz.R b/R/zzz.R index ebed3be..83a0f70 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -5,6 +5,7 @@ #' @import TestFunctions #' @import mlr3 #' @import paradox +#' @import ggplot2 #' #' @importFrom R6 R6Class #' @importFrom stats optimize diff --git a/man/LossFunction.Rd b/man/LossFunction.Rd index 3c35047..f423d3d 100644 --- a/man/LossFunction.Rd +++ b/man/LossFunction.Rd @@ -18,6 +18,14 @@ Loss function.} \item{\code{label}}{`character(1)`\cr Label of the loss function.} +\item{\code{properties}}{`character()`\cr +Additional properties of the loss function.} +} +\if{html}{\out{}} +} +\section{Active bindings}{ +\if{html}{\out{
}} +\describe{ \item{\code{properties}}{`character()`\cr Additional properties of the loss function.} } @@ -36,7 +44,7 @@ Additional properties of the loss function.} \subsection{Method \code{new()}}{ Creates a new instance of this [R6][R6::R6Class] class. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{LossFunction$new(id, label, properties, fun)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{LossFunction$new(id, label, task_type, fun)}\if{html}{\out{
}} } \subsection{Arguments}{ @@ -48,11 +56,11 @@ Unique identifier of the loss function.} \item{\code{label}}{(`character(1)`)\cr Label of the loss function.} -\item{\code{properties}}{(`character()`)\cr -Additional properties of the loss function.} - \item{\code{fun}}{(`function(y_true, y_pred, ...)`)\cr Loss function.} + +\item{\code{properties}}{(`character()`)\cr +Additional properties of the loss function.} } \if{html}{\out{
}} } diff --git a/man/Objective.Rd b/man/Objective.Rd index 8e58675..ac103bb 100644 --- a/man/Objective.Rd +++ b/man/Objective.Rd @@ -13,9 +13,9 @@ This class defines the objective that is used for optimization. \item{\code{label}}{(`character(1)` The label of the objective, i.e. a.} -\item{\code{limits_lower}}{(`numeric()`) The lower limits for each dimension.} +\item{\code{lower}}{(`numeric()`) The lower limits for each dimension.} -\item{\code{limits_upper}}{(`numeric()`) The upper limits for each dimension.} +\item{\code{upper}}{(`numeric()`) The upper limits for each dimension.} \item{\code{minimize}}{(`logical(1)`) Is the problem a minimization problem?} } @@ -57,8 +57,8 @@ Creates a new instance of this [R6][R6::R6Class] class. fun, label = "f", xdim, - limits_lower = NA, - limits_upper = NA, + lower = NA, + upper = NA, xtest = NULL, minimize = FALSE, ... @@ -76,9 +76,9 @@ Creates a new instance of this [R6][R6::R6Class] class. \item{\code{xdim}}{(`integer(1)`) The input dimension of `fun`. Use `xdim = NA` for an arbitrary input dimension.} -\item{\code{limits_lower}}{(`numeric(xdim)`) The lower boundaries for inputs to `fun`. Must} +\item{\code{lower}}{(`numeric(xdim)`) The lower boundaries for inputs to `fun`. Must} -\item{\code{limits_upper}}{(`numeric(xdim)`) The upper boundaries for inputs to `fun`. Must +\item{\code{upper}}{(`numeric(xdim)`) The upper boundaries for inputs to `fun`. Must be of length `xdim`.} \item{\code{xtest}}{(`numeric()`) Test value for `fun` during initialization. If not defined, @@ -147,7 +147,7 @@ Assert a numeric input if it is suitable or not. \describe{ \item{\code{x}}{(`numeric()`) Input value for `fun`.} -\item{\code{...}}{Additional arguments passed to `checkmate::assertNumeric(...)`.} +\item{\code{...}}{Additional arguments passed to `assertNumeric(...)`.} } \if{html}{\out{}} } diff --git a/man/Visualizer1D.Rd b/man/Visualizer1D.Rd index 72a1f72..13b2b4c 100644 --- a/man/Visualizer1D.Rd +++ b/man/Visualizer1D.Rd @@ -9,20 +9,68 @@ This class is used to create 1D visualizations. \section{Public fields}{ \if{html}{\out{
}} \describe{ -\item{\code{x}}{(`vector()`)\cr -x-values.} +\item{\code{x}}{(`numeric(n)`)\cr +x-values of function} -\item{\code{y}}{(`vector()`)\cr -y-values} +\item{\code{y}}{(`numeric(n)`)\cr +y-values of function} -\item{\code{plot_lab}}{(character(1)\cr -Label of the plot.} +\item{\code{title}}{(character(1)\cr +Title of plot} -\item{\code{x_lab}}{(character(1)\cr -Label of the x axis.} +\item{\code{lab_x}}{(character(1)\cr +Label of x-axis} -\item{\code{y_lab}}{(character(1)\cr -Label of the y axis.} +\item{\code{lab_y}}{(character(1)\cr +Label of y-axis} + +\item{\code{x}}{(`numeric(m)`)\cr +x-values of extra points to plot. +Use NULL if no points should be plotted.} + +\item{\code{y}}{(`numeric(m)`)\cr +y-values of extra points to plot. +Use NULL if no points should be plotted.} + +\item{\code{line_col}}{(character(1)\cr +Color of plotted line} + +\item{\code{line_width}}{(numeric(1)\cr +Width of plotted line} + +\item{\code{line_type}}{(character(1)\cr +Type of plotted line} + +\item{\code{points_col}}{(character(1)\cr +Color of plotted points} + +\item{\code{points_size}}{(numeric(1)\cr +Size of plotted points} + +\item{\code{points_shape}}{(integer(1)\cr +Shape of plotted points} + +\item{\code{points_alpha}}{(numeric(1)\cr +Alpha blending of plotted points} +} +\if{html}{\out{
}} +} +\section{Active bindings}{ +\if{html}{\out{
}} +\describe{ +\item{\code{x}}{(`numeric(n)`)\cr +x-values of function} + +\item{\code{y}}{(`numeric(n)`)\cr +y-values of function} + +\item{\code{x}}{(`numeric(m)`)\cr +x-values of extra points to plot. +Use NULL if no points should be plotted.} + +\item{\code{y}}{(`numeric(m)`)\cr +y-values of extra points to plot. +Use NULL if no points should be plotted.} } \if{html}{\out{
}} } @@ -30,10 +78,7 @@ Label of the y axis.} \subsection{Public methods}{ \itemize{ \item \href{#method-Visualizer1D-new}{\code{Visualizer1D$new()}} -\item \href{#method-Visualizer1D-init_layer_lines}{\code{Visualizer1D$init_layer_lines()}} -\item \href{#method-Visualizer1D-setLayout}{\code{Visualizer1D$setLayout()}} \item \href{#method-Visualizer1D-plot}{\code{Visualizer1D$plot()}} -\item \href{#method-Visualizer1D-save}{\code{Visualizer1D$save()}} \item \href{#method-Visualizer1D-clone}{\code{Visualizer1D$clone()}} } } @@ -43,62 +88,42 @@ Label of the y axis.} \subsection{Method \code{new()}}{ Creates a new instance of this [R6][R6::R6Class] class. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer1D$new(x, y, plot_lab = NULL, x_lab = "x", y_lab = "y")}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{Visualizer1D$new( + fun_x, + fun_y, + title = NULL, + lab_x = "x", + lab_y = "y", + points_x = NULL, + points_y = NULL +)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{x}}{(`numeric()`)\cr -x-values.} +\item{\code{title}}{(character(1)\cr +Title of plot} -\item{\code{y}}{(`numeric()`)\cr -y-values.} +\item{\code{lab_x}}{(character(1)\cr +Label of x-axis} -\item{\code{plot_lab}}{(character(1)\cr -Label of the plot.} +\item{\code{lab_y}}{(character(1)\cr +Label of y-axis} -\item{\code{x_lab}}{(character(1)\cr -Label of the x axis.} +\item{\code{points_x}}{(`numeric()`)\cr +x-values of extra points to plot. +Use NULL if no points should be plotted.} -\item{\code{y_lab}}{(character(1)\cr -Label of the y axis.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer1D-init_layer_lines}{}}} -\subsection{Method \code{init_layer_lines()}}{ -Initialize the plot with a line plot. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer1D$init_layer_lines(...)}\if{html}{\out{
}} -} +\item{\code{points_y}}{(`numeric()`)\cr +y-values of extra points to plot. +Use NULL if no points should be plotted.} -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{...}}{(`any`)\cr -Further arguments passed to `add_trace(...)`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer1D-setLayout}{}}} -\subsection{Method \code{setLayout()}}{ -Set the layout of the plotly plot. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer1D$setLayout(...)}\if{html}{\out{
}} -} +\item{\code{x}}{(`numeric()`)\cr +x-values of function} -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{...}}{(`any`)\cr -Layout options directly passed to `layout(...)`.} +\item{\code{y}}{(`numeric()`)\cr +y-values of function} } \if{html}{\out{
}} } @@ -107,29 +132,10 @@ Layout options directly passed to `layout(...)`.} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Visualizer1D-plot}{}}} \subsection{Method \code{plot()}}{ -Return the plot and hence plot it or do further processing. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Visualizer1D$plot()}\if{html}{\out{
}} } -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer1D-save}{}}} -\subsection{Method \code{save()}}{ -Save the plot by using plotlys `orca()` function. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer1D$save(...)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{...}}{(`any`)\cr -Further arguments passed to `orca()`.} -} -\if{html}{\out{
}} -} } \if{html}{\out{
}} \if{html}{\out{}} diff --git a/man/Visualizer1DModel.Rd b/man/Visualizer1DModel.Rd index 102076c..029df78 100644 --- a/man/Visualizer1DModel.Rd +++ b/man/Visualizer1DModel.Rd @@ -30,10 +30,7 @@ Learner used to train the model.} \if{html}{\out{
Inherited methods
}} @@ -46,9 +43,9 @@ Creates a new instance of this [R6][R6::R6Class] class. \if{html}{\out{
}}\preformatted{Visualizer1DModel$new( task, learner, - x1_limits = NULL, - padding = 0, - n_points = 100L + plot_data = FALSE, + xlim = NULL, + n_points = 100 )}\if{html}{\out{
}} } @@ -61,13 +58,6 @@ The task to train the model on.} \item{\code{learner}}{([mlr3::Learner])\cr The learner to train the model with.} -\item{\code{x1_limits}}{(`numeric(2)`)\cr -The x1 limits.} - -\item{\code{padding}}{(`numeric(1)`)\cr -A margin that is added to x1limits and x2limits. -The x1 margin is calculated by `max(x1lmits) - min(x1limits) * padding`.} - \item{\code{n_points}}{(`integer(1)`)\cr The number of generated point per dimension. Note that a grid of `npoints^2` values is generated and evaluated by `objective$eval(x)` to plot the surface.} diff --git a/man/Visualizer1DObj.Rd b/man/Visualizer1DObj.Rd new file mode 100644 index 0000000..c9add82 --- /dev/null +++ b/man/Visualizer1DObj.Rd @@ -0,0 +1,94 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Visualizer1DObj.R +\name{Visualizer1DObj} +\alias{Visualizer1DObj} +\title{Visualize Objective} +\description{ +This class is used to create visualizations of optimization traces. +} +\section{Super class}{ +\code{\link[vistool:Visualizer1D]{vistool::Visualizer1D}} -> \code{Visualizer1DObj} +} +\section{Public fields}{ +\if{html}{\out{
}} +\describe{ +\item{\code{objective}}{(`Objective`)\cr +The objective which was optimized. +This object is used to generate the surface/contour lines.} +} +\if{html}{\out{
}} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-Visualizer1DObj-new}{\code{Visualizer1DObj$new()}} +\item \href{#method-Visualizer1DObj-add_optimization_trace}{\code{Visualizer1DObj$add_optimization_trace()}} +\item \href{#method-Visualizer1DObj-clone}{\code{Visualizer1DObj$clone()}} +} +} +\if{html}{\out{ +
Inherited methods + +
+}} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer1DObj-new}{}}} +\subsection{Method \code{new()}}{ +Creates a new instance of this [R6][R6::R6Class] class. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer1DObj$new(objective, xlim = NULL, n_points = 100L)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{objective}}{(`Objective`)\cr +The objective which was optimized. +This object is used to generate the surface/contour lines.} + +\item{\code{n_points}}{(`integer(1)`)\cr +The number of generated point per dimension. +Note that a grid of `npoints^2` values is generated and evaluated by `objective$eval(x)` to plot the surface.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer1DObj-add_optimization_trace}{}}} +\subsection{Method \code{add_optimization_trace()}}{ +Add optimization trace to the plot. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer1DObj$add_optimization_trace(optimizer)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{optimizer}}{(`Optimizer`)\cr +The optimizer to add to the plot.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer1DObj-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer1DObj$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/Visualizer1DObjective.Rd b/man/Visualizer1DObjective.Rd deleted file mode 100644 index 06fc3b9..0000000 --- a/man/Visualizer1DObjective.Rd +++ /dev/null @@ -1,109 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Visualizer1DObjective.R -\name{Visualizer1DObjective} -\alias{Visualizer1DObjective} -\title{Visualize Objective} -\description{ -This class is used to create visualizations of optimization traces. -} -\section{Super class}{ -\code{\link[vistool:Visualizer1D]{vistool::Visualizer1D}} -> \code{Visualizer1DObjective} -} -\section{Public fields}{ -\if{html}{\out{
}} -\describe{ -\item{\code{objective}}{(`Objective`)\cr -The objective which was optimized. -This object is used to generate the surface/contour lines.} -} -\if{html}{\out{
}} -} -\section{Methods}{ -\subsection{Public methods}{ -\itemize{ -\item \href{#method-Visualizer1DObjective-new}{\code{Visualizer1DObjective$new()}} -\item \href{#method-Visualizer1DObjective-add_optimization_trace}{\code{Visualizer1DObjective$add_optimization_trace()}} -\item \href{#method-Visualizer1DObjective-clone}{\code{Visualizer1DObjective$clone()}} -} -} -\if{html}{\out{ -
Inherited methods - -
-}} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer1DObjective-new}{}}} -\subsection{Method \code{new()}}{ -Creates a new instance of this [R6][R6::R6Class] class. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer1DObjective$new( - objective, - x1_limits = NULL, - padding = 0, - n_points = 100L -)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{objective}}{(`Objective`)\cr -The objective which was optimized. -This object is used to generate the surface/contour lines.} - -\item{\code{x1_limits}}{(`numeric(2)`)\cr -The x1 limits.} - -\item{\code{padding}}{(`numeric(1)`)\cr -A margin that is added to x1limits and x2limits. -The x1 margin is calculated by `max(x1lmits) - min(x1limits) * padding`.} - -\item{\code{n_points}}{(`integer(1)`)\cr -The number of generated point per dimension. -Note that a grid of `npoints^2` values is generated and evaluated by `objective$eval(x)` to plot the surface.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer1DObjective-add_optimization_trace}{}}} -\subsection{Method \code{add_optimization_trace()}}{ -Add optimization trace to the plot. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer1DObjective$add_optimization_trace(optimizer)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{optimizer}}{(`Optimizer`)\cr -The optimizer to add to the plot.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer1DObjective-clone}{}}} -\subsection{Method \code{clone()}}{ -The objects of this class are cloneable with this method. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer1DObjective$clone(deep = FALSE)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{deep}}{Whether to make a deep clone.} -} -\if{html}{\out{
}} -} -} -} diff --git a/man/Visualizer2D.Rd b/man/Visualizer2D.Rd index 7f833ac..e8b80ea 100644 --- a/man/Visualizer2D.Rd +++ b/man/Visualizer2D.Rd @@ -15,13 +15,13 @@ List with the `x1` and `x2` grid.} \item{\code{zmat}}{(`matrix()`)\cr The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`.} -\item{\code{plot_lab}}{(character(1)\cr +\item{\code{title}}{(character(1)\cr Label of the plot.} -\item{\code{x1_lab}}{(character(1)\cr +\item{\code{lab_x1}}{(character(1)\cr Label of the x1 axis.} -\item{\code{x2_lab}}{(character(1)\cr +\item{\code{lab_x2}}{(character(1)\cr Label of the x2 axis.} \item{\code{z_lab}}{(character(1)\cr @@ -33,12 +33,7 @@ Label of the z axis.} \subsection{Public methods}{ \itemize{ \item \href{#method-Visualizer2D-new}{\code{Visualizer2D$new()}} -\item \href{#method-Visualizer2D-init_layer_contour}{\code{Visualizer2D$init_layer_contour()}} -\item \href{#method-Visualizer2D-init_layer_surface}{\code{Visualizer2D$init_layer_surface()}} -\item \href{#method-Visualizer2D-set_layout}{\code{Visualizer2D$set_layout()}} -\item \href{#method-Visualizer2D-set_scene}{\code{Visualizer2D$set_scene()}} \item \href{#method-Visualizer2D-plot}{\code{Visualizer2D$plot()}} -\item \href{#method-Visualizer2D-save}{\code{Visualizer2D$save()}} \item \href{#method-Visualizer2D-clone}{\code{Visualizer2D$clone()}} } } @@ -49,11 +44,11 @@ Label of the z axis.} Creates a new instance of this [R6][R6::R6Class] class. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Visualizer2D$new( - grid, - zmat, - plot_lab = NULL, - x1_lab = "x1", - x2_lab = "x2", + fun_x1, + fun_x2, + title = NULL, + lab_x1 = "x1", + lab_x2 = "x2", z_lab = "z" )}\if{html}{\out{
}} } @@ -61,129 +56,23 @@ Creates a new instance of this [R6][R6::R6Class] class. \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{grid}}{(`list()`)\cr -List with the `x1` and `x2` grid.} - -\item{\code{zmat}}{(`matrix()`)\cr -The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`.} - -\item{\code{plot_lab}}{(`character(1)`)\cr +\item{\code{title}}{(`character(1)`)\cr Label of the plot.} -\item{\code{x1_lab}}{(`character(1)`)\cr +\item{\code{lab_x1}}{(`character(1)`)\cr Label of the x1 axis.} -\item{\code{x2_lab}}{(`character(1)`)\cr +\item{\code{lab_x2}}{(`character(1)`)\cr Label of the x2 axis.} \item{\code{z_lab}}{(`character(1)`)\cr Label of the z axis.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2D-init_layer_contour}{}}} -\subsection{Method \code{init_layer_contour()}}{ -Initialize the plot with contour lines. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2D$init_layer_contour( - opacity = 0.8, - colorscale = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), - show_title = TRUE, - ... -)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{opacity}}{(`numeric(1)`)\cr -Opacity of the layer.} - -\item{\code{colorscale}}{(`list()`)\cr -The coloring of the contour.} - -\item{\code{show_title}}{(`logical(1)`)\cr -Indicator whether to show the title of the plot.} - -\item{\code{...}}{(`any`)\cr -Further arguments passed to `add_trace(...)`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2D-init_layer_surface}{}}} -\subsection{Method \code{init_layer_surface()}}{ -Initialize the plot as 3D surface. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2D$init_layer_surface( - opacity = 0.8, - colorscale = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), - show_contours = FALSE, - show_title = TRUE, - ... -)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{opacity}}{(`numeric(1)`)\cr -Opacity of the layer.} - -\item{\code{colorscale}}{(`list()`)\cr -The coloring of the surface.} - -\item{\code{show_contours}}{(`logical(1)`)\cr -Indicator whether to show the contours of the surface.} - -\item{\code{show_title}}{(`logical(1)`)\cr -Indicator whether to show the title of the plot.} - -\item{\code{...}}{(`any`)\cr -Further arguments passed to `add_trace(...)`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2D-set_layout}{}}} -\subsection{Method \code{set_layout()}}{ -Set the layout of the plotly plot. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2D$set_layout(...)}\if{html}{\out{
}} -} -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{...}}{Layout options directly passed to `layout(...)`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2D-set_scene}{}}} -\subsection{Method \code{set_scene()}}{ -Set the view for a 3D plot. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2D$set_scene(x, y, z)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{x}}{(`numeric(1)`) The view from which the "camera looks down" to the plot.} - -\item{\code{y}}{(`numeric(1)`) The view from which the "camera looks down" to the plot.} +\item{\code{grid}}{(`list()`)\cr +List with the `x1` and `x2` grid.} -\item{\code{z}}{(`numeric(1)`) The view from which the "camera looks down" to the plot.} +\item{\code{zmat}}{(`matrix()`)\cr +The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`.} } \if{html}{\out{
}} } @@ -192,28 +81,10 @@ Set the view for a 3D plot. \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Visualizer2D-plot}{}}} \subsection{Method \code{plot()}}{ -Return the plot and hence plot it or do further processing. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Visualizer2D$plot()}\if{html}{\out{
}} } -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2D-save}{}}} -\subsection{Method \code{save()}}{ -Save the plot by using plotlys `save_image()` function. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2D$save(...)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{...}}{Further arguments passed to `save_image()`.} -} -\if{html}{\out{
}} -} } \if{html}{\out{
}} \if{html}{\out{}} diff --git a/man/Visualizer2DModel.Rd b/man/Visualizer2DModel.Rd index c8d1b97..0706ad6 100644 --- a/man/Visualizer2DModel.Rd +++ b/man/Visualizer2DModel.Rd @@ -30,14 +30,9 @@ Learner used to train the model.} } } \if{html}{\out{ -
Inherited methods +
Inherited methods
}} diff --git a/man/Visualizer2DObjective.Rd b/man/Visualizer2DObj.Rd similarity index 66% rename from man/Visualizer2DObjective.Rd rename to man/Visualizer2DObj.Rd index 29550ee..3e39cbf 100644 --- a/man/Visualizer2DObjective.Rd +++ b/man/Visualizer2DObj.Rd @@ -1,13 +1,13 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Visualizer2DObjective.R -\name{Visualizer2DObjective} -\alias{Visualizer2DObjective} +% Please edit documentation in R/Visualizer2DObj.R +\name{Visualizer2DObj} +\alias{Visualizer2DObj} \title{Visualize Objective} \description{ This class is used to create visualizations and animations of optimization traces. } \section{Super class}{ -\code{\link[vistool:Visualizer2D]{vistool::Visualizer2D}} -> \code{Visualizer2DObjective} +\code{\link[vistool:Visualizer2D]{vistool::Visualizer2D}} -> \code{Visualizer2DObj} } \section{Public fields}{ \if{html}{\out{
}} @@ -21,33 +21,28 @@ This object is used to generate the surface/contour lines.} \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-Visualizer2DObjective-new}{\code{Visualizer2DObjective$new()}} -\item \href{#method-Visualizer2DObjective-add_optimization_trace}{\code{Visualizer2DObjective$add_optimization_trace()}} -\item \href{#method-Visualizer2DObjective-add_layer_taylor}{\code{Visualizer2DObjective$add_layer_taylor()}} -\item \href{#method-Visualizer2DObjective-add_layer_hessian}{\code{Visualizer2DObjective$add_layer_hessian()}} -\item \href{#method-Visualizer2DObjective-animate}{\code{Visualizer2DObjective$animate()}} -\item \href{#method-Visualizer2DObjective-clone}{\code{Visualizer2DObjective$clone()}} +\item \href{#method-Visualizer2DObj-new}{\code{Visualizer2DObj$new()}} +\item \href{#method-Visualizer2DObj-add_optimization_trace}{\code{Visualizer2DObj$add_optimization_trace()}} +\item \href{#method-Visualizer2DObj-add_layer_taylor}{\code{Visualizer2DObj$add_layer_taylor()}} +\item \href{#method-Visualizer2DObj-add_layer_hessian}{\code{Visualizer2DObj$add_layer_hessian()}} +\item \href{#method-Visualizer2DObj-animate}{\code{Visualizer2DObj$animate()}} +\item \href{#method-Visualizer2DObj-clone}{\code{Visualizer2DObj$clone()}} } } \if{html}{\out{ -
Inherited methods +
Inherited methods
}} \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2DObjective-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer2DObj-new}{}}} \subsection{Method \code{new()}}{ Creates a new instance of this [R6][R6::R6Class] class. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2DObjective$new( +\if{html}{\out{
}}\preformatted{Visualizer2DObj$new( objective, x1_limits = NULL, x2_limits = NULL, @@ -81,12 +76,12 @@ Note that a grid of `npoints^2` values is generated and evaluated by `objective$ } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2DObjective-add_optimization_trace}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer2DObj-add_optimization_trace}{}}} \subsection{Method \code{add_optimization_trace()}}{ Add an optimization trace. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2DObjective$add_optimization_trace( +\if{html}{\out{
}}\preformatted{Visualizer2DObj$add_optimization_trace( opt, line_color = colSampler(), mcolor_out = "black", @@ -147,12 +142,12 @@ The colors for the markers.} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2DObjective-add_layer_taylor}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer2DObj-add_layer_taylor}{}}} \subsection{Method \code{add_layer_taylor()}}{ Add a Taylor approximation (for 1 and 2 degrees). \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2DObjective$add_layer_taylor( +\if{html}{\out{
}}\preformatted{Visualizer2DObj$add_layer_taylor( x0, degree = 2, x1margin = 0, @@ -192,17 +187,12 @@ Additional parameter passed to `add_surface()`.} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2DObjective-add_layer_hessian}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer2DObj-add_layer_hessian}{}}} \subsection{Method \code{add_layer_hessian()}}{ Add two "arrows" as eigenvectors of the Hessian. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2DObjective$add_layer_hessian( - x0, - x1length = 0.1, - x2length = 0.1, - ... -)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{Visualizer2DObj$add_layer_hessian(x0, x1length = 0.1, x2length = 0.1, ...)}\if{html}{\out{
}} } \subsection{Arguments}{ @@ -224,12 +214,12 @@ Additional arguments passed to `add_trace`.} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2DObjective-animate}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer2DObj-animate}{}}} \subsection{Method \code{animate()}}{ Create an animation of `$plot()`. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2DObjective$animate( +\if{html}{\out{
}}\preformatted{Visualizer2DObj$animate( dir = "animation", nframes = 10L, view_start = list(x = 1, y = 1, z = 1), @@ -270,12 +260,12 @@ Additional arguments passed to `$save(...)`.} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2DObjective-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer2DObj-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2DObjective$clone(deep = FALSE)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{Visualizer2DObj$clone(deep = FALSE)}\if{html}{\out{
}} } \subsection{Arguments}{ diff --git a/man/VisualizerLossFunction.Rd b/man/VisualizerLossFunction.Rd deleted file mode 100644 index 6b56814..0000000 --- a/man/VisualizerLossFunction.Rd +++ /dev/null @@ -1,152 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/VisualizerLossFunction.R -\name{VisualizerLossFunction} -\alias{VisualizerLossFunction} -\title{Visualize Loss Function} -\description{ -This class is used to create visualizations of loss functions. -} -\section{Public fields}{ -\if{html}{\out{
}} -\describe{ -\item{\code{loss_function}}{[LossFunction]\cr -Loss function.} - -\item{\code{loss}}{(`numeric()`)\cr -Loss values.} - -\item{\code{y_pred}}{`numeric()`\cr -Predicted values.} -} -\if{html}{\out{
}} -} -\section{Methods}{ -\subsection{Public methods}{ -\itemize{ -\item \href{#method-VisualizerLossFunction-new}{\code{VisualizerLossFunction$new()}} -\item \href{#method-VisualizerLossFunction-init_layer_lines}{\code{VisualizerLossFunction$init_layer_lines()}} -\item \href{#method-VisualizerLossFunction-set_layout}{\code{VisualizerLossFunction$set_layout()}} -\item \href{#method-VisualizerLossFunction-plot}{\code{VisualizerLossFunction$plot()}} -\item \href{#method-VisualizerLossFunction-save}{\code{VisualizerLossFunction$save()}} -\item \href{#method-VisualizerLossFunction-clone}{\code{VisualizerLossFunction$clone()}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-VisualizerLossFunction-new}{}}} -\subsection{Method \code{new()}}{ -Creates a new instance of this [R6][R6::R6Class] class. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{VisualizerLossFunction$new(loss_function, y_pred, y_true, ...)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{loss_function}}{[LossFunction]\cr -Loss function.} - -\item{\code{y_pred}}{(`numeric()`)\cr -Predicted values.} - -\item{\code{y_true}}{(`numeric(1)`)\cr -True value.} - -\item{\code{...}}{(`any`)\cr -Additional arguments passed to the loss function.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-VisualizerLossFunction-init_layer_lines}{}}} -\subsection{Method \code{init_layer_lines()}}{ -Initialize the plot with a line plot. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{VisualizerLossFunction$init_layer_lines( - width = 2, - color = "rgb(160,82,45)", - ... -)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{width}}{(`integer(1)`)\cr -Width of the line.} - -\item{\code{color}}{(`character(1)`)\cr -Color of the line.} - -\item{\code{...}}{(`any`)\cr -Further arguments passed to `add_trace(...)`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-VisualizerLossFunction-set_layout}{}}} -\subsection{Method \code{set_layout()}}{ -Set the layout of the plotly plot. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{VisualizerLossFunction$set_layout(...)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{...}}{(`any`)\cr -Layout options directly passed to `layout(...)`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-VisualizerLossFunction-plot}{}}} -\subsection{Method \code{plot()}}{ -Return the plot and hence plot it or do further processing. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{VisualizerLossFunction$plot()}\if{html}{\out{
}} -} - -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-VisualizerLossFunction-save}{}}} -\subsection{Method \code{save()}}{ -Save the plot by using plotlys `orca()` function. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{VisualizerLossFunction$save(...)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{...}}{(`any`)\cr -Further arguments passed to `orca()`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-VisualizerLossFunction-clone}{}}} -\subsection{Method \code{clone()}}{ -The objects of this class are cloneable with this method. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{VisualizerLossFunction$clone(deep = FALSE)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{deep}}{Whether to make a deep clone.} -} -\if{html}{\out{
}} -} -} -} diff --git a/man/VisualizerLossFuns.Rd b/man/VisualizerLossFuns.Rd new file mode 100644 index 0000000..8d33d3a --- /dev/null +++ b/man/VisualizerLossFuns.Rd @@ -0,0 +1,77 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/VisualizerLossFuns.R +\name{VisualizerLossFuns} +\alias{VisualizerLossFuns} +\title{Visualizer for Losses} +\description{ +Visualize one or multiple loss functions. +} +\section{Public fields}{ +\if{html}{\out{
}} +\describe{ +\item{\code{loss_function}}{[LossFunction]\cr +Loss function.} +} +\if{html}{\out{
}} +} +\section{Active bindings}{ +\if{html}{\out{
}} +\describe{ +\item{\code{loss_function}}{[LossFunction]\cr +Loss function.} +} +\if{html}{\out{
}} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-VisualizerLossFuns-new}{\code{VisualizerLossFuns$new()}} +\item \href{#method-VisualizerLossFuns-plot}{\code{VisualizerLossFuns$plot()}} +\item \href{#method-VisualizerLossFuns-clone}{\code{VisualizerLossFuns$clone()}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VisualizerLossFuns-new}{}}} +\subsection{Method \code{new()}}{ +Creates a new instance of this [R6][R6::R6Class] class. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{VisualizerLossFuns$new(losses)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{loss_function}}{[LossFunction]\cr +Loss function.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VisualizerLossFuns-plot}{}}} +\subsection{Method \code{plot()}}{ +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{VisualizerLossFuns$plot()}\if{html}{\out{
}} +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-VisualizerLossFuns-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{VisualizerLossFuns$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/as_visualizer.Rd b/man/as_visualizer.Rd deleted file mode 100644 index 0c9db9c..0000000 --- a/man/as_visualizer.Rd +++ /dev/null @@ -1,65 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/as_visualizer.R -\name{as_visualizer} -\alias{as_visualizer} -\alias{as_visualizer.Task} -\alias{as_visualizer.Objective} -\alias{as_visualizer.LossFunction} -\title{Convert to visualizer} -\usage{ -as_visualizer(x, ...) - -\method{as_visualizer}{Task}( - x, - learner, - x1_limits = NULL, - x2_limits = NULL, - padding = 0, - n_points = 100L, - ... -) - -\method{as_visualizer}{Objective}( - x, - x1_limits = NULL, - x2_limits = NULL, - padding = 0, - n_points = 100L, - ... -) - -\method{as_visualizer}{LossFunction}(x, y_pred, y_true, ...) -} -\arguments{ -\item{x}{(`any`)\cr -Object to convert to a visualizer.} - -\item{...}{(`any`)\cr -Additional arguments.} - -\item{learner}{(`mlr3::Learner`)\cr -The learner to train the model with.} - -\item{x1_limits}{(`numeric(2)`)\cr -The x1 limits.} - -\item{x2_limits}{(`numeric(2)`)\cr -The x2 limits.} - -\item{padding}{(`numeric(1)`)\cr -A margin that is added to x1limits and x2limits. -The x1 margin is calculated by `max(x1lmits) - min(x1limits) * padding`.} - -\item{n_points}{(`integer(1)`)\cr -The number of generated point per dimension. -Note that a grid of `npoints^2` values is generated and evaluated by `objective$eval(x)` to plot the surface.} - -\item{y_pred}{(`numeric()`)\cr -Predicted values.} - -\item{y_true}{(`numeric(1)`)\cr -True value.} -} -\description{ -This function converts to a visualizer. -} diff --git a/man/mlr_learners_regr.lm_formula.Rd b/man/mlr_learners_regr.lm_formula.Rd index 608b347..506a0ab 100644 --- a/man/mlr_learners_regr.lm_formula.Rd +++ b/man/mlr_learners_regr.lm_formula.Rd @@ -22,7 +22,7 @@ Calls [stats::lm()].
Inherited methods
  • mlr3::Learner$base_learner()
  • -
  • mlr3::Learner$estimate_memory_usage()
  • +
  • mlr3::Learner$encapsulate()
  • mlr3::Learner$format()
  • mlr3::Learner$help()
  • mlr3::Learner$predict()
  • diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..3c9459a --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,12 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview +# * https://testthat.r-lib.org/articles/special-files.html + +library(testthat) +library(vistool) + +test_check("vistool") diff --git a/tests/testthat/test-Visualizer2DModel.R b/tests/testthat/test-Visualizer2DModel.R new file mode 100644 index 0000000..af2f725 --- /dev/null +++ b/tests/testthat/test-Visualizer2DModel.R @@ -0,0 +1,39 @@ +test_that("multiplication works", { + require_namespaces("mlr3learners") + + task = tsk("mtcars") + task$select(c("gear", "cyl")) + + learner = lrn("regr.svm") + + vis = Visualizer2DModel$new(task, learner) + + vis$plot() +}) + +test_that("multiplication works", { + require_namespaces("mlr3learners") + + task = tsk("mtcars") + task$select(c("gear", "cyl")) + + learner = lrn("regr.svm") + + vis = Visualizer2DModel$new(task, learner) + + vis$plot(training_data = TRUE) +}) + +test_that("multiplication works", { + require_namespaces("mlr3learners") + + task = tsk("spam") + task$select(c("you", "credit")) + + learner = lrn("classif.svm", predict_type = "prob") + + vis = Visualizer2DModel$new(task, learner) + + vis$plot() + vis$plot(training_data = TRUE) +}) diff --git a/tests/testthat/test-Visualizer2DObj.R b/tests/testthat/test-Visualizer2DObj.R new file mode 100644 index 0000000..bdadb50 --- /dev/null +++ b/tests/testthat/test-Visualizer2DObj.R @@ -0,0 +1,9 @@ +test_that("multiplication works", { + require_namespaces("mlr3learners") + + obj_branin = obj("TF_branin") + + vis = Visualizer2DObj$new(obj_branin) + + vis$plot() +}) From 3051b6eed89db7790fb471625b3a1e1f9b2dafab Mon Sep 17 00:00:00 2001 From: be-marc Date: Tue, 12 Nov 2024 02:10:53 +0100 Subject: [PATCH 3/3] ... --- NAMESPACE | 3 + R/Visualizer1D.R | 11 +- R/Visualizer1DModel.R | 33 +- R/Visualizer2D.R | 36 +- R/Visualizer2DModel.R | 30 +- R/Visualizer3D.R | 276 +++++++++++++++ R/Visualizer3DModel.R | 173 ++++++++++ R/Visualizer3DObj.R | 425 ++++++++++++++++++++++++ R/as_visualizer.R | 0 man/Visualizer1DModel.Rd | 4 +- man/Visualizer2D.Rd | 57 ++-- man/Visualizer2DModel.Rd | 57 +--- man/Visualizer2DObj.Rd | 188 ----------- man/Visualizer3D.Rd | 235 +++++++++++++ man/Visualizer3DModel.Rd | 148 +++++++++ man/Visualizer3DObjective.Rd | 289 ++++++++++++++++ man/colSampler.Rd | 2 +- tests/testthat/test-Visualizer1DModel.R | 25 ++ tests/testthat/test-Visualizer2DModel.R | 25 +- tests/testthat/test-Visualizer2DObj.R | 3 +- 20 files changed, 1695 insertions(+), 325 deletions(-) create mode 100644 R/Visualizer3D.R create mode 100644 R/Visualizer3DModel.R create mode 100644 R/Visualizer3DObj.R delete mode 100644 R/as_visualizer.R create mode 100644 man/Visualizer3D.Rd create mode 100644 man/Visualizer3DModel.Rd create mode 100644 man/Visualizer3DObjective.Rd create mode 100644 tests/testthat/test-Visualizer1DModel.R diff --git a/NAMESPACE b/NAMESPACE index 28ff780..4bb8686 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -15,6 +15,9 @@ export(Visualizer1DObj) export(Visualizer2D) export(Visualizer2DModel) export(Visualizer2DObj) +export(Visualizer3D) +export(Visualizer3DModel) +export(Visualizer3DObjective) export(VisualizerLossFuns) export(as.data.table) export(assertStepSizeControl) diff --git a/R/Visualizer1D.R b/R/Visualizer1D.R index 5fb4a50..f78cf85 100644 --- a/R/Visualizer1D.R +++ b/R/Visualizer1D.R @@ -92,7 +92,15 @@ Visualizer1D = R6::R6Class("Visualizer1D", #' @param points_y (`numeric()`)\cr #' y-values of extra points to plot. #' Use NULL if no points should be plotted. - initialize = function(fun_x, fun_y, title = NULL, lab_x = "x", lab_y = "y", points_x = NULL, points_y = NULL) { + initialize = function( + fun_x, + fun_y, + title = NULL, + lab_x = "x", + lab_y = "y", + points_x = NULL, + points_y = NULL + ) { self$fun_x = assert_numeric(fun_x) self$fun_y = assert_numeric(fun_y) self$title = assert_character(title, null.ok = TRUE) @@ -107,7 +115,6 @@ Visualizer1D = R6::R6Class("Visualizer1D", self$points_col = "black" self$points_size = 2 self$points_alpha = 0.3 - return(invisible(self)) }, # FIXME: set better defaults here to make plot nicer, maybe ask lukas diff --git a/R/Visualizer1DModel.R b/R/Visualizer1DModel.R index d1b6e11..a2c1853 100644 --- a/R/Visualizer1DModel.R +++ b/R/Visualizer1DModel.R @@ -20,9 +20,6 @@ Visualizer1DModel = R6::R6Class("Visualizer1DModel", inherit = Visualizer1D, #' Learner used to train the model. learner = NULL, - # FIXME: add that we can plot data - plot_data = NULL, - n_points = NULL, #' @description @@ -32,15 +29,21 @@ Visualizer1DModel = R6::R6Class("Visualizer1DModel", inherit = Visualizer1D, #' The task to train the model on. #' @param learner ([mlr3::Learner])\cr #' The learner to train the model with. - initialize = function(task, learner, plot_data = FALSE, xlim = NULL, n_points = 100) { + initialize = function( + task, + learner, + xlim = NULL, + n_points = 100, + training_points = FALSE + ) { # FIXME: doc complete class, not all args are doced here self$task = assert_task(task) fnames = task$feature_names if (length(fnames) != 1) stop("Task must have exactly 1 feature") self$learner = assert_learner(learner, task = self$task) - assert_flag(plot_data) assert_count(n_points) + assert_flag(training_points) # train learner on task self$learner$train(task) @@ -55,15 +58,19 @@ Visualizer1DModel = R6::R6Class("Visualizer1DModel", inherit = Visualizer1D, y_pred = self$learner$predict_newdata(newdata)$response title = sprintf("%s on %s", self$learner$id, self$task$id) - points_x = NULL; points_y = NULL - if (plot_data) { - points_x = x_train - points_y = y_train - } - super$initialize(fun_x = x_pred, fun_y = y_pred, - title = title, lab_x = fnames[1], lab_y = task$target_names, - points_x = points_x, points_y = points_y) + super$initialize( + fun_x = x_pred, + fun_y = y_pred, + title = title, + lab_x = fnames[1], + lab_y = task$target_names) + + if (training_points) { + data = task$data() + self$points_x = data[[self$lab_x]] + self$points_y = data[[task$target_names]] + } } ) ) diff --git a/R/Visualizer2D.R b/R/Visualizer2D.R index da6501d..b5584d0 100644 --- a/R/Visualizer2D.R +++ b/R/Visualizer2D.R @@ -39,6 +39,8 @@ Visualizer2D = R6::R6Class("Visualizer2D", #' @field points_x2 (`numeric()`)\cr points_x2 = NULL, + #' @field points_y (`numeric()`)\cr + #' y-values of points. points_y = NULL, #' @description @@ -58,7 +60,15 @@ Visualizer2D = R6::R6Class("Visualizer2D", #' Label of x-axis. #' @param lab_y (`character(1)`) #' Label of y-axis. - initialize = function(fun_x1, fun_x2, fun_y, title = NULL, lab_x1 = "x1", lab_x2 = "x2", lab_y = "y") { + initialize = function( + fun_x1, + fun_x2, + fun_y, + title = NULL, + lab_x1 = "x1", + lab_x2 = "x2", + lab_y = "y" + ) { self$fun_x1 = assert_numeric(fun_x1) self$fun_x2 = assert_numeric(fun_x2) self$fun_y = assert_numeric(fun_y) @@ -69,16 +79,28 @@ Visualizer2D = R6::R6Class("Visualizer2D", }, plot = function() { - data = data.table(fun_x1 = self$fun_x1, fun_x2 = self$fun_x2, fun_y = self$fun_y) + data = data.table( + fun_x1 = self$fun_x1, + fun_x2 = self$fun_x2, + fun_y = self$fun_y) p = ggplot(data, aes(x = fun_x1, y = fun_x2, z = fun_y)) + geom_contour_filled() + geom_contour(color = "white") + - labs(title = self$title, x = self$lab_x1, y = self$lab_x2) - - if (!is.null(self$points_x1)) { - data = data.table(points_x1 = self$points_x1, points_x2 = self$points_x2, points_y = self$points_y) - p = p + geom_point(data = data, aes(x = points_x1, y = points_x2, color = self$points_y), size = 5) + labs(title = self$title, x = self$lab_x1, y = self$lab_x2) + + theme_minimal() + + if (!is.null(self$points_x1) && !is.null(self$points_x2) && !is.null(self$points_y)) { + data = data.table( + points_x1 = self$points_x1, + points_x2 = self$points_x2, + points_y = self$points_y) + + p = p + geom_point(aes(x = points_x1, y = points_x2, color = points_y), + data = data, + size = 2, + inherit.aes = FALSE) + + scale_color_viridis_d() } return(p) diff --git a/R/Visualizer2DModel.R b/R/Visualizer2DModel.R index 3da7502..3ffc203 100644 --- a/R/Visualizer2DModel.R +++ b/R/Visualizer2DModel.R @@ -35,8 +35,8 @@ Visualizer2DModel = R6::R6Class("Visualizer2DModel", x1_limits = NULL, x2_limits = NULL, padding = 0, - n_points = 100L - training_data = FALSE + n_points = 100L, + training_points = FALSE ) { self$task = assert_task(task) @@ -44,6 +44,7 @@ Visualizer2DModel = R6::R6Class("Visualizer2DModel", assert_numeric(x1_limits, len = 2, null.ok = TRUE) assert_numeric(x2_limits, len = 2, null.ok = TRUE) assert_count(n_points) + assert_flag(training_points) lab_x1 = self$task$feature_names[1] lab_x2 = self$task$feature_names[2] data = task$data() @@ -59,6 +60,7 @@ Visualizer2DModel = R6::R6Class("Visualizer2DModel", y = self$learner$predict_newdata(newdata)[[self$learner$predict_type]] if (self$learner$predict_type == "prob") y = y[, task$positive] + super$initialize( fun_x1 = newdata[, lab_x1, with = FALSE][[1]], fun_x2 = newdata[, lab_x2, with = FALSE][[1]], @@ -69,34 +71,12 @@ Visualizer2DModel = R6::R6Class("Visualizer2DModel", lab_y = task$target_names ) - if (training_data) { - - } - }, - - plot = function() { - if (training_data) { + if (training_points) { data = task$data() self$points_x1 = data[[lab_x1]] self$points_x2 = data[[lab_x2]] self$points_y = data[[task$target_names]] } - - - if (training_data) { - data = task$data() - # if (self$learner$predict_type == "prob") points_y = as.integer(points_y) - 1 - browser() - super$plot() + - geom_point(aes( - x = .data[[self$task$feature_names[1]]], - y = .data[[self$task$feature_names[2]]], - color = .data[[self$task$target_names]]), - data = data, size = 5, inherit.aes = FALSE) + - scale_color_viridis_c() - } else { - super$plot() - } } ) ) diff --git a/R/Visualizer3D.R b/R/Visualizer3D.R new file mode 100644 index 0000000..8946a86 --- /dev/null +++ b/R/Visualizer3D.R @@ -0,0 +1,276 @@ +#' @title Visualize Base Class +#' +#' @description +#' This class is used to create 3D visualizations. +#' +#' @template param_x1_limits +#' @template param_x2_limits +#' @template param_padding +#' @template param_n_points +#' +#' @export +Visualizer3D = R6::R6Class("Visualizer3D", + public = list( + + #' @field grid (`list()`)\cr + #' List with the `x1` and `x2` grid. + grid = NULL, + + #' @field zmat (`matrix()`)\cr + #' The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`. + zmat = NULL, + + #' @field plot_lab (character(1)\cr + #' Label of the plot. + plot_lab = NULL, + + #' @field x1_lab (character(1)\cr + #' Label of the x1 axis. + x1_lab = NULL, + + #' @field x2_lab (character(1)\cr + #' Label of the x2 axis. + x2_lab = NULL, + + #' @field z_lab (character(1)\cr + #' Label of the z axis. + z_lab = NULL, + + #' @description + #' Creates a new instance of this [R6][R6::R6Class] class. + #' + #' @param grid (`list()`)\cr + #' List with the `x1` and `x2` grid. + #' @param zmat (`matrix()`)\cr + #' The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`. + #' @param plot_lab (`character(1)`)\cr + #' Label of the plot. + #' @param x1_lab (`character(1)`)\cr + #' Label of the x1 axis. + #' @param x2_lab (`character(1)`)\cr + #' Label of the x2 axis. + #' @param z_lab (`character(1)`)\cr + #' Label of the z axis. + initialize = function(grid, zmat, plot_lab = NULL, x1_lab = "x1", x2_lab = "x2", z_lab = "z") { + self$grid = assert_list(grid) + self$zmat = assert_matrix(zmat) + self$plot_lab = assert_character(plot_lab, null.ok = TRUE) + self$x1_lab = assert_character(x1_lab) + self$x2_lab = assert_character(x2_lab) + self$z_lab = assert_character(z_lab) + return(invisible(self)) + }, + + #' @description + #' Initialize the plot with contour lines. + #' + #' @param opacity (`numeric(1)`)\cr + #' Opacity of the layer. + #' @param colorscale (`list()`)\cr + #' The coloring of the contour. + #' @param show_title (`logical(1)`)\cr + #' Indicator whether to show the title of the plot. + #' @param ... (`any`)\cr + #' Further arguments passed to `add_trace(...)`. + init_layer_contour = function(opacity = 0.8, colorscale = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), show_title = TRUE, ...) { + assert_number(opacity, lower = 0, upper = 1) + assert_list(colorscale) + assert_flag(show_title) + + private$.vbase = c(as.list(environment()), list(...)) + private$.layer_primary = "contour" + + llp = list(x = self$grid$x1, y = self$grid$x2, z = self$zmat) + private$.plot = plot_ly() %>% + add_trace( + name = self$plot_lab, + showlegend = TRUE, + showscale = TRUE, + x = llp$x, + y = llp$y, + z = t(llp$z), + type = "contour", + opacity = opacity, + colorscale = colorscale, + ... + ) %>% + layout( + title = if (show_title) self$plot_lab else NULL, + xaxis = list(title = self$x1_lab), + yaxis = list(title = self$x2_lab)) + + if (! private$.freeze_plot) { # Used in animate to not overwrite the + private$.opts = list() # plot over and over again when calling + private$.layer_arrow = list() # `$initLayerXXX`. + } + + return(invisible(self)) + }, + + #' @description + #' Initialize the plot as 3D surface. + #' + #' @param opacity (`numeric(1)`)\cr + #' Opacity of the layer. + #' @param colorscale (`list()`)\cr + #' The coloring of the surface. + #' @param show_title (`logical(1)`)\cr + #' Indicator whether to show the title of the plot. + #' @param show_contours (`logical(1)`)\cr + #' Indicator whether to show the contours of the surface. + #' @param ... (`any`)\cr + #' Further arguments passed to `add_trace(...)`. + init_layer_surface = function(opacity = 0.8, colorscale = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), show_contours = FALSE, show_title = TRUE, ...) { + assert_number(opacity, lower = 0, upper = 1) + assert_list(colorscale) + assert_flag(show_title) + + private$.vbase = c(as.list(environment()), list(...)) + private$.layer_primary = "surface" + + contours = if (show_contours) { + list( + z = list( + show = TRUE, + project = list(z = TRUE), + usecolormap = TRUE) + ) + } else NULL + + llp = list(x = self$grid$x1, y = self$grid$x2, z = self$zmat) + private$.plot = plot_ly() %>% + add_trace( + name = self$plot_lab, + showlegend = FALSE, + showscale = FALSE, + x = llp$x, + y = llp$y, + z = t(llp$z), + type = "surface", + opacity = opacity, + colorscale = colorscale, + contours = contours, + ... + ) %>% + layout( + title = if (show_title) self$plot_lab else NULL, + scene = list( + xaxis = list(title = self$x1_lab), + yaxis = list(title = self$x2_lab), + zaxis = list(title = self$z_lab) + ) + ) + + if (! private$.freeze_plot) { # Used in animate to not overwrite the plot over and over again. + private$.opts = list() + private$.layer_arrow = list() + } + + return(invisible(self)) + }, + + #' @description Set the layout of the plotly plot. + #' @param ... Layout options directly passed to `layout(...)`. + set_layout = function(...) { + private$.layout = list(...) + private$.plot = private$.plot %>% layout(...) + + return(invisible(self)) + }, + + #' @description Set the view for a 3D plot. + #' @param x (`numeric(1)`) The view from which the "camera looks down" to the plot. + #' @param y (`numeric(1)`) The view from which the "camera looks down" to the plot. + #' @param z (`numeric(1)`) The view from which the "camera looks down" to the plot. + set_scene = function(x, y, z) { + if (is.null(private$.plot)) self$init_layer_surface() + assert_number(x) + assert_number(y) + assert_number(z) + + if (private$.layer_primary != "surface") { + stop("Scene can only be set for `surface` plots") + } + + private$.plot = private$.plot %>% + layout(scene = list(camera = list(eye = list(x = x, y = y, z = z)))) + + return(invisible(self)) + }, + + #' @description Return the plot and hence plot it or do further processing. + plot = function() { + if (is.null(private$.plot)) self$init_layer_surface() + return(private$.plot) + }, + + + #' @description Save the plot by using plotlys `save_image()` function. + #' @param ... Further arguments passed to `save_image()`. + save = function(...) { + if (is.null(private$.plot)) self$init_layer_surface() + save_image(private$.plot, ...) + } + ), + private = list( + # @field .layer_primary (`character(1)`) The id of the primary layer. Used to determine + # the trace setup. + .layer_primary = NULL, + + # @field .layer_arrow (`list()`) Arguments passed to `$addLayerArrow()` to reconstruct the plot for animations. + .layer_arrow = list(), + + # @field .plot (`plot_ly()`) The plot. + .plot = NULL, + + # @field .opts (`list(Optimizer)`) List of optimizers used to add traces. Each `$initLayerXXX()` + # resets this list. An optimizer is added after each call to `$addLayerOptimizationTrace()`. + # this private field is exclusively used to create animations with `$animate()`. + .opts = list(), + + .vbase = list(), + + .layout = list(), + + # @field .freeze_plot (`logical(1)`) Indicator whether to freeze saving the plot elements. + .freeze_plot = FALSE, + + checkInit = function() { + if (is.null(private$.plot)) { + stop("Initialize plot with `initLayer*`") + } + return(invisible(TRUE)) + }, + checkInput = function(x) { + if (private$.layer_primary == "surface") { + return(checkmate::assertNumeric(x, len = 3L)) + } + if (private$.layer_primary == "contour") { + return(checkmate::assertNumeric(x, len = 3L)) + } + stop("Error in `$checkInput()`") + } + ) +) + +#' Randomly generate colors +#' @description Helper function to generate RGB colors. +#' @param alpha (`numeric(1)`) The alpha value. If `!is.null` the used prefix is 'rgba' instead of 'rgb'. +#' @return A character of length one containing the RGB color. +#' @import plotly +#' @import colorspace +#' @export +colSampler = function(alpha = NULL) { + checkmate::assertNumber(alpha, lower = 0, upper = 1, null.ok = TRUE) + r = sample(seq(0, 255), 1) + g = sample(seq(0, 255), 1) + b = sample(seq(0, 255), 1) + + if (is.null(alpha)) { + rgb = "rgb" + } else { + rgb = "rgba" + } + clr = sprintf("%s(%s)", rgb, paste(c(r, g, b, alpha), collapse = ", ")) + return(clr) +} diff --git a/R/Visualizer3DModel.R b/R/Visualizer3DModel.R new file mode 100644 index 0000000..c1a8efc --- /dev/null +++ b/R/Visualizer3DModel.R @@ -0,0 +1,173 @@ + +#' @title Visualize Model +#' +#' @description +#' This class is used to create 3D visualizations of learners and tasks. +#' +#' @template param_x1_limits +#' @template param_x2_limits +#' @template param_padding +#' @template param_n_points +#' +#' @export +Visualizer3DModel = R6::R6Class("Visualizer3DModel", + inherit = Visualizer3D, + public = list( + + #' @field task (`mlr3::Task`)\cr + #' Task used to train the model. + task = NULL, + + #' @field learner (`mlr3::Learner`)\cr + #' Learner used to train the model. + learner = NULL, + + #' @description + #' Creates a new instance of this [R6][R6::R6Class] class. + #' + #' @param task ([mlr3::Task])\cr + #' The task to train the model on. + #' @param learner ([mlr3::Learner])\cr + #' The learner to train the model with. + initialize = function(task, learner, x1_limits = NULL, x2_limits = NULL, padding = 0, n_points = 100L) { + self$task = assert_task(task) + self$learner = assert_learner(learner, task = self$task) + assert_numeric(x1_limits, len = 2, null.ok = TRUE) + assert_numeric(x2_limits, len = 2, null.ok = TRUE) + assert_count(n_points) + x1 = self$task$feature_names[1] + x2 = self$task$feature_names[2] + data = task$data() + self$learner$train(task) + + x1_limits = range(data[, x1, with = FALSE]) + x2_limits = range(data[, x2, with = FALSE]) + + grid = list( + x1 = seq(x1_limits[1] - padding, x1_limits[2] + padding, length.out = n_points), + x2 = seq(x2_limits[1] - padding, x2_limits[2] + padding, length.out = n_points) + ) + + newdata = set_names(CJ(grid$x1, grid$x2), self$task$feature_names) + z = self$learner$predict_newdata(newdata)[[self$learner$predict_type]] + if (self$learner$predict_type == "prob") { + pos_class = self$task$positive + z = z[, pos_class] + } + zmat = matrix(z, nrow = n_points, ncol = n_points, byrow = FALSE) + + super$initialize( + grid = grid, + zmat = zmat, + plot_lab = sprintf("%s on %s", self$learner$id, self$task$id), + x1_lab = x1, + x2_lab = x2, + z_lab = task$target_names + ) + + return(invisible(self)) + }, + + #' @description + #' Adds the training data to the plot. + #' + #' @param size (`numeric(1)`)\cr + #' Size of the points. + #' @param color (`character(1)`)\cr + #' Color of the points. + #' @param ... (`any`)\cr + #' Further arguments passed to `add_trace(...)`. + add_training_data = function(size = 5, color = "grey",...) { + if (is.null(private$.plot)) self$init_layer_surface() + data = self$task$data() + x1 = data[, self$task$feature_names[1], with = FALSE][[1]] + x2 = data[, self$task$feature_names[2], with = FALSE][[1]] + z = data[, self$task$target_names, with = FALSE][[1]] + if (self$learner$predict_type == "prob") z = as.integer(z) - 1 + + + if (private$.layer_primary == "contour") { + private$.plot = private$.plot %>% + add_trace( + x = x1, + y = x2, + type = "scatter", + mode = "markers", + marker = list( + size = 10, + color = z, + cmin = min(self$zmat), + cmax = max(self$zmat), + colorscale = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), + line = list(color = 'black', width = 2), + showscale = FALSE), + text = ~paste("x:", x1, "\ny:", x2, " \nz:", z), + hoverinfo = 'text', + ... + ) + } else { + private$.plot = private$.plot %>% + add_trace( + x = x1, + y = x2, + z = z, + type = "scatter3d", + mode = "markers", + marker = list(size = 5, color = grey), + ... + ) + } + + + + return(invisible(self)) + }, + + #' @description + #' Adds the decision boundary to the plot. + #' + #' @param threshold (`numeric(1)`)\cr + #' Threshold for the decision boundary. + #' @param ... (`any`)\cr + #' Further arguments passed to `add_trace(...)`. + add_decision_boundary = function(threshold = 0.5, ...) { + if (is.null(private$.plot)) self$init_layer_surface() + z = matrix(threshold, nrow = nrow(self$zmat), ncol = ncol(self$zmat), byrow = TRUE) + + if (private$.layer_primary == "contour") { + llp = list(x = self$grid$x1, y = self$grid$x2, z = self$zmat) + private$.plot = private$.plot %>% + add_trace( + name = "decision boundary", + autocontour = FALSE, + showlegend = FALSE, + showscale = FALSE, + x = llp$x, + y = llp$y, + z = t(llp$z), + type = "contour", + colorscale = list(c(0, 1), c("rgb(0,0,0)", "rgb(0,0,0)")), + ncontours = 1, + contours = list( + start = threshold, + end = threshold, + coloring = "lines" + ), + line = list( + color = "black", + width = 3 + ), + ...) + } else { + private$.plot = private$.plot %>% + add_surface( + x = self$grid$x1, + y = self$grid$x2, + z = z, + colorscale = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), + showscale = FALSE, + ...) + } + } + ) +) diff --git a/R/Visualizer3DObj.R b/R/Visualizer3DObj.R new file mode 100644 index 0000000..a5962b9 --- /dev/null +++ b/R/Visualizer3DObj.R @@ -0,0 +1,425 @@ +#' @title Visualize Objective +#' +#' @description +#' This class is used to create visualizations and animations of optimization traces. +#' +#' @template param_x1_limits +#' @template param_x2_limits +#' @template param_padding +#' @template param_n_points +#' +#' @export +Visualizer3DObjective = R6::R6Class("Visualizer3DObjective", + inherit = Visualizer3D, + public = list( + + #' @field objective (`Objective`)\cr + #' The objective which was optimized. + #' This object is used to generate the surface/contour lines. + objective = NULL, + + #' @description + #' Creates a new instance of this [R6][R6::R6Class] class. + #' + #' @param objective (`Objective`)\cr + #' The objective which was optimized. + #' This object is used to generate the surface/contour lines. + initialize = function(objective, x1_limits = NULL, x2_limits = NULL, padding = 0, n_points = 100L) { + self$objective = assert_r6(objective, "Objective") + assert_numeric(x1_limits, len = 2, null.ok = TRUE) + assert_numeric(x2_limits, len = 2, null.ok = TRUE) + assert_numeric(padding) + assert_count(n_points) + + if (objective$xdim != 2) { + stopf("`Visualizer2D` requires 2-dimensional inputs, but `objective$xdim = %s`", objective$xdim) + } + + x1_limits = x1_limits %??% c(objective$limits_lower[1], objective$limits_upper[1]) + x2_limits = x2_limits %??% c(objective$limits_lower[2], objective$limits_upper[2]) + + if (any(is.na(x1_limits)) || any(is.na(x2_limits))) { + stop("Limits could not be extracted from the objective. Please use `x_limits`.") + } + + x1_pad = (x1_limits[2] - x1_limits[1]) * padding + x2_pad = (x2_limits[2] - x2_limits[1]) * padding + + grid = list( + x1 = unique(seq(x1_limits[1] - x1_pad, x1_limits[2] + x1_pad, length.out = n_points)), + x2 = unique(seq(x2_limits[1] - x2_pad, x2_limits[2] + x2_pad, length.out = n_points))) + + zmat = outer(grid$x1, grid$x2, function(x, y) { + xin = cbind(x, y) + apply(xin, 1, function(x) self$objective$eval(x)) + }) + + super$initialize( + grid = grid, + zmat = zmat, + plot_lab = self$objective$label, + x1_lab = "x1", + x2_lab = "x2", + z_lab = "y" + ) + + return(invisible(self)) + }, + + #' @description + #' Add an optimization trace. + #' + #' @param opt (`Optimizer`)\cr + #' The optimizer from which the archive is extracted and used to plot the trace. + #' @param line_color (`character(1)`)\cr + #' The color of the trace. + #' @param mcolor_out (`character(1)`)\cr + #' The outer line color of the marker. + #' @param npoints (`integer(1)`)\cr + #' The number of used points from the archive. + #' Default is `NULL` which means that all points are used. + #' If set, a sequence from 1 to `nrow(opt$archive)` is created. + #' @param npmax (`integer(1)`)\cr + #' The number of points used from the sequence `seq_len(nrow(opt$archive))[seq_len(npmax)]` + #' @param name (`character(1)`)\cr + #' The name of the trace in the legend. + #' Default is `NULL` which means that the name is pasted from `opt$id` and `objective$id`. + #' @param offset (`numeric(3)`)\cr + #' Trace shift in direction (x, y, z). + #' @param add_marker_at (`integer()`)\cr + #' Vector of iterations at which a marker is added. + #' @param marker_shape (`character()`)\cr + #' Vector indicating the shape of the markers. + #' If `length(marker_shape) == 1`, all markers get the same shape. + #' The other option is to specify all markers individually by passing a vector of `length(add_marker_at)`. + #' For a list of all shapes see `schema(F)$traces$XXX$attributes$marker$symbol$values` with `XXX` one of `scatter` or `scatter3d`. + #' If `marker_shape = NA`, no marker are added. + #' @param marker_color (`character()`)\cr + #' The colors for the markers. + #' @param ... Further arguments passed to `add_trace(...)`. + add_optimization_trace = function(opt, line_color = colSampler(), mcolor_out = "black", npoints = NULL, npmax = NULL, name = NULL, offset = NULL, add_marker_at = 1, marker_shape = "circle", marker_color = NULL, ...) { + assert_r6(opt, "Optimizer") + assert_count(npoints, null.ok = TRUE) + assert_count(npmax, null.ok = TRUE) + assert_string(line_color) + if (is.null(private$.plot)) self$init_layer_surface() + + if (nrow(opt$archive) == 0) { + stop("No optimization trace in `opt$archive`. Did you forget to call `opt$optimize(steps)`?") + } + + if (private$.layer_primary == "contour") { + checkmate::assertNumeric(offset, len = 2L, null.ok = TRUE) + if (is.null(offset)) { + offset = rep(0, 2) + } + offset[3] = 0 + } + if (private$.layer_primary == "surface") { + checkmate::assertNumeric(offset, len = 3L, null.ok = TRUE) + if (is.null(offset)) { + offset = rep(0, 3) + } + } + + # Catch additional arguments: + aargs = list(...) + + if (! private$.freeze_plot) { # Just set by animate to not save the optimizer over and over again for each frame. + private$.opts = c(private$.opts, list(c(as.list(environment()), aargs))) + } + + # Assert marker styling: + checkmate::assertIntegerish(add_marker_at, lower = 1, upper = nrow(opt$archive)) + if (is.null(marker_shape)) marker_shape = NA + if (length(marker_shape) == 1) marker_shape = rep(marker_shape, length(add_marker_at)) + mvals = NULL + if (private$.layer_primary == "contour") { + mvals = schema(F)$traces$scatter$attributes$marker$symbol$values + } + if (private$.layer_primary == "surface") { + mvals = schema(F)$traces$scatter3d$attributes$marker$symbol$values + } + invisible(lapply(marker_shape, function(marker_shape) checkmate::assertChoice(marker_shape, choices = c(mvals, NA)))) + + if (is.null(marker_color)) marker_color = line_color + if (length(marker_color) == 1) { + marker_color = rep(marker_color, length(marker_shape)) + } + checkmate::assertCharacter(marker_color, len = length(marker_shape), null.ok = TRUE) + + # Define marker coordinates for plotting: + xmat = do.call(rbind, c(opt$archive$x_in[1], opt$archive$x_out)) + xmarkers = data.frame(x = xmat[, 1] + offset[1], y = xmat[, 2] + offset[2], + z = c(opt$archive$fval_in[1], opt$archive$fval_out) + offset[3]) + if (is.null(npoints)) { + npoints = nrow(xmarkers) + } + if (is.null(npmax)) { + npmax = nrow(xmarkers) + if (npmax > nrow(xmarkers)) { + npmax = nrow(xmarkers) + } + } + # Cut marker after npmax iterations (if specified): + xmr = xmarkers[unique(round(seq(1, nrow(xmarkers), length.out = npoints))), ] + xmr = xmr[seq_len(npmax), ] + add_marker_at = add_marker_at[add_marker_at <= npmax] + + ptype = NULL + if (is.null(name)) { + name = paste0(opt$id, " on ", opt$objective$id) + } + + # Define the plotting arguments as list, so we can call `do.call` with these arguments. This is + # more comfortable due to just one call to `add_trace`. Additionally, it is easier to control + # different default stylings (such as line width) and to recreate the layer with the stored arguments: + if (private$.layer_primary == "surface") { + ptype = "scatter3d" + pargs = list( + name = name, + x = xmr$x, + y = xmr$y, + z = xmr$z, + marker = list(color = line_color, line = list(color = mcolor_out, width = 6)), + line = list(color = line_color, width = 8)) + } + if (private$.layer_primary == "contour") { + ptype = "scatter" + pargs = list( + name = name, + x = xmr$x, + y = xmr$y, + marker = list(color = line_color, size = 12, line = list(color = mcolor_out, width = 2)), + line = list(color = line_color, width = 2)) + } + if (is.null(ptype)) { + stop("No known plot mode") + } + pargs$type = ptype + + # Add optimization traces as lines to the plot: + private$.plot = do.call(add_trace, c(list(private$.plot), + mlr3misc::insert_named(mlr3misc::remove_named(pargs, "marker"), aargs), + list(mode = "lines"))) + + # Now add marker to the lines. Marker are added at `add_marker_at` iterations + # and with the specified shape and color: + pargs = list( + x = xmarkers$x[add_marker_at], + y = xmarkers$y[add_marker_at], + z = xmarkers$z[add_marker_at], + mode = "markers", + type = ptype, + marker = insert_named(pargs$marker, list(symbol = marker_shape, color = marker_color)), + showlegend = FALSE) + if (private$.layer_primary == "contour") { + pargs$z = NULL + } + private$.plot = do.call(add_trace, c(list(private$.plot), pargs)) + + return(invisible(self)) + }, + + #' @description + #' Add a Taylor approximation (for 1 and 2 degrees). + #' + #' @param x0 (`numeric()) `\cr + #' The point around which the approximation is done. + #' @param degree (`integer(1)`)\cr + #' The degree of the approximation (only 1 and 2 is implemented). + #' @param x1margin (`numeric(1)`)\cr + #' The "length" of the hyperplane in direction x1. + #' @param x2margin (`numeric(1)`)\cr + #' The "length" of the hyperplane in direction x2. + #' @param npoints_per_dim (`integer(1)`)\cr + #' Number of points per dimension for the plotting grid. + #' @param zlim (`numeric(2)`)\cr + #' The limits for z. + #' Can be helpful if the hyperplane as a huge z range and therefore the plot looks ugly. + #' @param ... (`any`)\cr + #' Additional parameter passed to `add_surface()`. + add_layer_taylor = function(x0, degree = 2, x1margin = 0, x2margin = 0, npoints_per_dim = 20L, zlim = NULL, ...) { + private$checkInit() + if (private$.layer_primary != "surface") stop("Atm just available for `surface`") + checkmate::assertNumeric(x0, len = 2L) + checkmate::assertIntegerish(degree, len = 1, lower = 1, upper = 2) + checkmate::assertNumber(x1margin) + checkmate::assertNumber(x2margin) + + #checkmate::assertNumeric(x1limits, len = 2L, null.ok = TRUE) + #checkmate::assertNumeric(x2limits, len = 2L, null.ok = TRUE) + + #if (is.null(x1limits)) x1limits = x0[1] + c(-0.05, 0.05) + #if (is.null(x2limits)) x2limits = x0[2] + c(-0.05, 0.05) + + f0 = self$objective$eval(x0) + g = self$objective$grad(x0) + h = self$objective$hess(x0) + + # Create box based on the gradient at x0: + # - Normalize vector to length x1margin / 2 + # - Calculate perpendicular vector + # - These vectors define the rotation + gn = g / l2norm(g) + gp = rbind(c(0, -1), c(1, 0)) %*% gn + + gn = gn * x1margin / 2 + gp = gp * x2margin / 2 + + # - Create grid in (0,0) x (1,1) and rotate w.r.t. to gn and gp: + rotation = cbind(gn, gp) + square = as.matrix(expand.grid(x = seq(0, 1, len = npoints_per_dim), y = seq(0, 1, len = npoints_per_dim))) + grid = square %*% rotation + grid[, 1] = grid[, 1] - max(grid[, 1]) + (max(grid[, 1]) - min(grid[, 1])) / 2 + x0[1] + grid[, 2] = grid[, 2] - max(grid[, 2]) + (max(grid[, 2]) - min(grid[, 2])) / 2 + x0[2] + + fapp = function(x) { + out = f0 + crossprod(g, x - x0) * f0 + if (degree == 2) { + out = out + 0.5 * f0 * t(x - x0) %*% h %*% (x - x0) + } + return(as.numeric(out)) + } + fappV = function(x, y) { + X = cbind(x = x, y = y) + apply(X, 1, fapp) + } + z = outer(X = grid[,1], Y = grid[,2], FUN = function(x, y) fappV(x, y)) + if (! is.null(zlim)) { + checkmate::assertNumeric(zlim, len = 2L) + z[! between(z, zlim[1], zlim[2])] = NA + } + + private$.plot = private$.plot %>% add_surface(x = grid[, 1], y = grid[, 2], z = t(z), showscale = FALSE, ...) + }, + + #' @description + #' Add two "arrows" as eigenvectors of the Hessian. + #' + #' @param x0 (`numeric(2)`)\cr + #' The point at which the Hessian is calculated. + #' @param x1length (`numeric(1)`)\cr + #' The length of the first eigenvector. + #' @param x2length (`numeric(1)`)\cr + #' The length of the second eigenvector. + #' @param ... (`any`)\cr + #' Additional arguments passed to `add_trace`. + add_layer_hessian = function(x0, x1length = 0.1, x2length = 0.1, ...) { + private$checkInit() + checkmate::assertNumeric(x0, len = 2L) + checkmate::assertNumber(x1length) + checkmate::assertNumber(x2length) + + f0 = self$objective$eval(x0) + h = self$objective$hess(x0) + ev = eigen(h)$vectors + + v1 = ev[, 1] + v2 = ev[, 2] + + if (private$.layer_primary == "contour") { + # Transpose x and y to macht contour: + v1 = v1 * x1length + x0 + v2 = v2 * x2length + x0 + + mx = c(v1[1], x0[1], v2[1]) + my = c(v1[2], x0[2], v2[2]) + + private$.plot = private$.plot %>% add_trace(x = mx, y = my, mode = "lines", type = "scatter", showlegend = FALSE, ...) + } + if (private$.layer_primary == "surface") { + v1 = v1 * x1length + x0 + v2 = v2 * x2length + x0 + + v0 = c(x0, f0) + v1 = c(v1, f0) + v2 = c(v2, f0) + + # Order is important to have the angle: + marker = cbind(v1, v0, v2) + + private$.plot = private$.plot %>% add_trace(x = marker[1, ], y = marker[2, ], z = marker[3, ], mode = "lines", type = "scatter3d", showlegend = FALSE, ...) + } + }, + + #' @description + #' Create an animation of `$plot()`. + #' + #' @param dir (`character(1)`)\cr + #' The directory in which all the images are saved. + #' @param nframes (`integer(1)`)\cr + #' The number of frames. + #' @param view_start (`list()`)\cr + #' The start view of the animation. + #' @param view_end (`list()`)\cr + #' The end view of the animation. + #' @param fext (`character(1)`)\cr + #' The file extension (default is `png`). + #' @param stops (`integer()`)\cr + #' The step / iteration in the archives of the optimizers added by `$addLayerOptimizationTrace()` at which a frame is taken. + #' Must have exact the same length as defined in `nframes`. + #' By default, a sequence with equidistant points is generated for `stops`. + #' @param ... (`any`)\cr + #' Additional arguments passed to `$save(...)`. + animate = function(dir = "animation", nframes = 10L, view_start = list(x = 1, y = 1, z = 1), + view_end = list(x = 1, y = 1, z = 1), fext = "png", stops = NULL, ...) { + + checkmate::assertDirectory(dir) + checkmate::assertCount(nframes) + checkmate::assertList(view_start) + checkmate::assertList(view_end) + checkmate::assertIntegerish(stops, lower = 1, len = nframes, null.ok = TRUE) + + if (! all((names(view_start) == c("x", "y", "z")) | (names(view_end) == c("x", "y", "z")))) { + stop("View needs `x`, `y`, and `z` coordinates.") + } + invisible(lapply(c(view_start, view_end), checkmate::assertNumber)) + + views = list( + x = seq(view_start$x, view_end$x, len = nframes), + y = seq(view_start$y, view_end$y, len = nframes), + z = seq(view_start$z, view_end$z, len = nframes)) + + if (is.null(stops)) { + maxcalls = max(vapply(private$.opts, function(oo) nrow(oo$opt$archive), integer(1))) + stops = unique(round(seq(1, maxcalls, len = nframes))) + } + + plot_temp = private$.plot + private$.freeze_plot = TRUE + + for (i in seq_len(nframes)) { + + is = stringr::str_pad(i, width = 4, pad = "0") + fname = sprintf("%s/frame-%s.%s", dir, is, fext) + + if (private$.layer_primary == "surface") { + do.call(self$initLayerSurface, private$.vbase) + } + if (private$.layer_primary == "contour") { + do.call(self$initLayerContour, private$.vbase) + } + if (is.null(private$.layer_primary)) { + stop("No figure was created jet") + } + + for (j in seq_along(private$.opts)) { + do.call(self$addLayerOptimizationTrace, mlr3misc::insert_named(private$.opts[[j]], list(npmax = stops[i]))) + } + + if (private$.layer_primary == "surface") { + self$setScene(x = views$x[i], y = views$y[i], z = views$z[i]) + } + do.call(self$setLayout, private$.layout) + + self$save(fname, ...) + } + + private$.freeze_plot = FALSE + private$.plot = plot_temp + + message(sprintf("Files stored in '%s'. Use, e.g., ImageMagic (http://www.imagemagick.org/) with `convert -delay 20 -loop 0 %s/*.%s myimage.gif` to create gif with 20 ms frames.", dir, dir, fext)) + } + ) +) diff --git a/R/as_visualizer.R b/R/as_visualizer.R deleted file mode 100644 index e69de29..0000000 diff --git a/man/Visualizer1DModel.Rd b/man/Visualizer1DModel.Rd index 029df78..7c05faa 100644 --- a/man/Visualizer1DModel.Rd +++ b/man/Visualizer1DModel.Rd @@ -43,9 +43,9 @@ Creates a new instance of this [R6][R6::R6Class] class. \if{html}{\out{
    }}\preformatted{Visualizer1DModel$new( task, learner, - plot_data = FALSE, xlim = NULL, - n_points = 100 + n_points = 100, + training_points = FALSE )}\if{html}{\out{
    }} } diff --git a/man/Visualizer2D.Rd b/man/Visualizer2D.Rd index e8b80ea..3527af8 100644 --- a/man/Visualizer2D.Rd +++ b/man/Visualizer2D.Rd @@ -9,23 +9,26 @@ This class is used to create 2D visualizations. \section{Public fields}{ \if{html}{\out{
    }} \describe{ -\item{\code{grid}}{(`list()`)\cr -List with the `x1` and `x2` grid.} +\item{\code{fun_x1}}{(`numeric(n)`)} -\item{\code{zmat}}{(`matrix()`)\cr -The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`.} +\item{\code{fun_x2}}{(`numeric(n)`)} -\item{\code{title}}{(character(1)\cr -Label of the plot.} +\item{\code{fun_y}}{(`numeric(n)`)} -\item{\code{lab_x1}}{(character(1)\cr -Label of the x1 axis.} +\item{\code{title}}{(`character(1)`)} -\item{\code{lab_x2}}{(character(1)\cr -Label of the x2 axis.} +\item{\code{lab_x1}}{(`character(1)`)} -\item{\code{z_lab}}{(character(1)\cr -Label of the z axis.} +\item{\code{lab_x2}}{(`character(1)`)} + +\item{\code{lab_y}}{(`character(1)`)} + +\item{\code{points_x1}}{(`numeric()`)\cr} + +\item{\code{points_x2}}{(`numeric()`)\cr} + +\item{\code{points_y}}{(`numeric()`)\cr +y-values of points.} } \if{html}{\out{
    }} } @@ -46,33 +49,37 @@ Creates a new instance of this [R6][R6::R6Class] class. \if{html}{\out{
    }}\preformatted{Visualizer2D$new( fun_x1, fun_x2, + fun_y, title = NULL, lab_x1 = "x1", lab_x2 = "x2", - z_lab = "z" + lab_y = "y" )}\if{html}{\out{
    }} } \subsection{Arguments}{ \if{html}{\out{
    }} \describe{ -\item{\code{title}}{(`character(1)`)\cr -Label of the plot.} +\item{\code{fun_x1}}{(`numeric()`) +x-values of function.} + +\item{\code{fun_x2}}{(`numeric()`) +x-values of function.} -\item{\code{lab_x1}}{(`character(1)`)\cr -Label of the x1 axis.} +\item{\code{fun_y}}{(`numeric()`) +y-values of function.} -\item{\code{lab_x2}}{(`character(1)`)\cr -Label of the x2 axis.} +\item{\code{title}}{(`character(1)`) +Title of plot.} -\item{\code{z_lab}}{(`character(1)`)\cr -Label of the z axis.} +\item{\code{lab_x1}}{(`character(1)`) +Label of x-axis.} -\item{\code{grid}}{(`list()`)\cr -List with the `x1` and `x2` grid.} +\item{\code{lab_x2}}{(`character(1)`) +Label of x-axis.} -\item{\code{zmat}}{(`matrix()`)\cr -The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`.} +\item{\code{lab_y}}{(`character(1)`) +Label of y-axis.} } \if{html}{\out{
    }} } diff --git a/man/Visualizer2DModel.Rd b/man/Visualizer2DModel.Rd index 0706ad6..e9ea8c6 100644 --- a/man/Visualizer2DModel.Rd +++ b/man/Visualizer2DModel.Rd @@ -24,8 +24,6 @@ Learner used to train the model.} \subsection{Public methods}{ \itemize{ \item \href{#method-Visualizer2DModel-new}{\code{Visualizer2DModel$new()}} -\item \href{#method-Visualizer2DModel-add_training_data}{\code{Visualizer2DModel$add_training_data()}} -\item \href{#method-Visualizer2DModel-add_decision_boundary}{\code{Visualizer2DModel$add_decision_boundary()}} \item \href{#method-Visualizer2DModel-clone}{\code{Visualizer2DModel$clone()}} } } @@ -48,7 +46,8 @@ Creates a new instance of this [R6][R6::R6Class] class. x1_limits = NULL, x2_limits = NULL, padding = 0, - n_points = 100L + n_points = 100L, + training_points = FALSE )}\if{html}{\out{
}} } @@ -79,58 +78,6 @@ Note that a grid of `npoints^2` values is generated and evaluated by `objective$ } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2DModel-add_training_data}{}}} -\subsection{Method \code{add_training_data()}}{ -Adds the training data to the plot. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2DModel$add_training_data(size = 5, color = "grey", ...)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{size}}{(`numeric(1)`)\cr -Size of the points.} - -\item{\code{color}}{(`character(1)`)\cr -Color of the points.} - -\item{\code{...}}{(`any`)\cr -Further arguments passed to `add_trace(...)`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2DModel-add_decision_boundary}{}}} -\subsection{Method \code{add_decision_boundary()}}{ -Adds the decision boundary to the plot. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2DModel$add_decision_boundary( - threshold = 0.5, - surfacecolor = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), - ... -)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{threshold}}{(`numeric(1)`)\cr -Threshold for the decision boundary.} - -\item{\code{surfacecolor}}{(`list()`)\cr -The coloring of the surface.} - -\item{\code{...}}{(`any`)\cr -Further arguments passed to `add_trace(...)`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Visualizer2DModel-clone}{}}} \subsection{Method \code{clone()}}{ diff --git a/man/Visualizer2DObj.Rd b/man/Visualizer2DObj.Rd index 3e39cbf..9595b30 100644 --- a/man/Visualizer2DObj.Rd +++ b/man/Visualizer2DObj.Rd @@ -22,10 +22,6 @@ This object is used to generate the surface/contour lines.} \subsection{Public methods}{ \itemize{ \item \href{#method-Visualizer2DObj-new}{\code{Visualizer2DObj$new()}} -\item \href{#method-Visualizer2DObj-add_optimization_trace}{\code{Visualizer2DObj$add_optimization_trace()}} -\item \href{#method-Visualizer2DObj-add_layer_taylor}{\code{Visualizer2DObj$add_layer_taylor()}} -\item \href{#method-Visualizer2DObj-add_layer_hessian}{\code{Visualizer2DObj$add_layer_hessian()}} -\item \href{#method-Visualizer2DObj-animate}{\code{Visualizer2DObj$animate()}} \item \href{#method-Visualizer2DObj-clone}{\code{Visualizer2DObj$clone()}} } } @@ -76,190 +72,6 @@ Note that a grid of `npoints^2` values is generated and evaluated by `objective$ } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2DObj-add_optimization_trace}{}}} -\subsection{Method \code{add_optimization_trace()}}{ -Add an optimization trace. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2DObj$add_optimization_trace( - opt, - line_color = colSampler(), - mcolor_out = "black", - npoints = NULL, - npmax = NULL, - name = NULL, - offset = NULL, - add_marker_at = 1, - marker_shape = "circle", - marker_color = NULL, - ... -)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{opt}}{(`Optimizer`)\cr -The optimizer from which the archive is extracted and used to plot the trace.} - -\item{\code{line_color}}{(`character(1)`)\cr -The color of the trace.} - -\item{\code{mcolor_out}}{(`character(1)`)\cr -The outer line color of the marker.} - -\item{\code{npoints}}{(`integer(1)`)\cr -The number of used points from the archive. -Default is `NULL` which means that all points are used. -If set, a sequence from 1 to `nrow(opt$archive)` is created.} - -\item{\code{npmax}}{(`integer(1)`)\cr -The number of points used from the sequence `seq_len(nrow(opt$archive))[seq_len(npmax)]`} - -\item{\code{name}}{(`character(1)`)\cr -The name of the trace in the legend. -Default is `NULL` which means that the name is pasted from `opt$id` and `objective$id`.} - -\item{\code{offset}}{(`numeric(3)`)\cr -Trace shift in direction (x, y, z).} - -\item{\code{add_marker_at}}{(`integer()`)\cr -Vector of iterations at which a marker is added.} - -\item{\code{marker_shape}}{(`character()`)\cr -Vector indicating the shape of the markers. -If `length(marker_shape) == 1`, all markers get the same shape. -The other option is to specify all markers individually by passing a vector of `length(add_marker_at)`. -For a list of all shapes see `schema(F)$traces$XXX$attributes$marker$symbol$values` with `XXX` one of `scatter` or `scatter3d`. -If `marker_shape = NA`, no marker are added.} - -\item{\code{marker_color}}{(`character()`)\cr -The colors for the markers.} - -\item{\code{...}}{Further arguments passed to `add_trace(...)`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2DObj-add_layer_taylor}{}}} -\subsection{Method \code{add_layer_taylor()}}{ -Add a Taylor approximation (for 1 and 2 degrees). -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2DObj$add_layer_taylor( - x0, - degree = 2, - x1margin = 0, - x2margin = 0, - npoints_per_dim = 20L, - zlim = NULL, - ... -)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{x0}}{(`numeric()) `\cr -The point around which the approximation is done.} - -\item{\code{degree}}{(`integer(1)`)\cr -The degree of the approximation (only 1 and 2 is implemented).} - -\item{\code{x1margin}}{(`numeric(1)`)\cr -The "length" of the hyperplane in direction x1.} - -\item{\code{x2margin}}{(`numeric(1)`)\cr -The "length" of the hyperplane in direction x2.} - -\item{\code{npoints_per_dim}}{(`integer(1)`)\cr -Number of points per dimension for the plotting grid.} - -\item{\code{zlim}}{(`numeric(2)`)\cr -The limits for z. -Can be helpful if the hyperplane as a huge z range and therefore the plot looks ugly.} - -\item{\code{...}}{(`any`)\cr -Additional parameter passed to `add_surface()`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2DObj-add_layer_hessian}{}}} -\subsection{Method \code{add_layer_hessian()}}{ -Add two "arrows" as eigenvectors of the Hessian. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2DObj$add_layer_hessian(x0, x1length = 0.1, x2length = 0.1, ...)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{x0}}{(`numeric(2)`)\cr -The point at which the Hessian is calculated.} - -\item{\code{x1length}}{(`numeric(1)`)\cr -The length of the first eigenvector.} - -\item{\code{x2length}}{(`numeric(1)`)\cr -The length of the second eigenvector.} - -\item{\code{...}}{(`any`)\cr -Additional arguments passed to `add_trace`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-Visualizer2DObj-animate}{}}} -\subsection{Method \code{animate()}}{ -Create an animation of `$plot()`. -\subsection{Usage}{ -\if{html}{\out{
}}\preformatted{Visualizer2DObj$animate( - dir = "animation", - nframes = 10L, - view_start = list(x = 1, y = 1, z = 1), - view_end = list(x = 1, y = 1, z = 1), - fext = "png", - stops = NULL, - ... -)}\if{html}{\out{
}} -} - -\subsection{Arguments}{ -\if{html}{\out{
}} -\describe{ -\item{\code{dir}}{(`character(1)`)\cr -The directory in which all the images are saved.} - -\item{\code{nframes}}{(`integer(1)`)\cr -The number of frames.} - -\item{\code{view_start}}{(`list()`)\cr -The start view of the animation.} - -\item{\code{view_end}}{(`list()`)\cr -The end view of the animation.} - -\item{\code{fext}}{(`character(1)`)\cr -The file extension (default is `png`).} - -\item{\code{stops}}{(`integer()`)\cr -The step / iteration in the archives of the optimizers added by `$addLayerOptimizationTrace()` at which a frame is taken. -Must have exact the same length as defined in `nframes`. -By default, a sequence with equidistant points is generated for `stops`.} - -\item{\code{...}}{(`any`)\cr -Additional arguments passed to `$save(...)`.} -} -\if{html}{\out{
}} -} -} -\if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Visualizer2DObj-clone}{}}} \subsection{Method \code{clone()}}{ diff --git a/man/Visualizer3D.Rd b/man/Visualizer3D.Rd new file mode 100644 index 0000000..3b1328e --- /dev/null +++ b/man/Visualizer3D.Rd @@ -0,0 +1,235 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Visualizer3D.R +\name{Visualizer3D} +\alias{Visualizer3D} +\title{Visualize Base Class} +\description{ +This class is used to create 3D visualizations. +} +\section{Public fields}{ +\if{html}{\out{
}} +\describe{ +\item{\code{grid}}{(`list()`)\cr +List with the `x1` and `x2` grid.} + +\item{\code{zmat}}{(`matrix()`)\cr +The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`.} + +\item{\code{plot_lab}}{(character(1)\cr +Label of the plot.} + +\item{\code{x1_lab}}{(character(1)\cr +Label of the x1 axis.} + +\item{\code{x2_lab}}{(character(1)\cr +Label of the x2 axis.} + +\item{\code{z_lab}}{(character(1)\cr +Label of the z axis.} +} +\if{html}{\out{
}} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-Visualizer3D-new}{\code{Visualizer3D$new()}} +\item \href{#method-Visualizer3D-init_layer_contour}{\code{Visualizer3D$init_layer_contour()}} +\item \href{#method-Visualizer3D-init_layer_surface}{\code{Visualizer3D$init_layer_surface()}} +\item \href{#method-Visualizer3D-set_layout}{\code{Visualizer3D$set_layout()}} +\item \href{#method-Visualizer3D-set_scene}{\code{Visualizer3D$set_scene()}} +\item \href{#method-Visualizer3D-plot}{\code{Visualizer3D$plot()}} +\item \href{#method-Visualizer3D-save}{\code{Visualizer3D$save()}} +\item \href{#method-Visualizer3D-clone}{\code{Visualizer3D$clone()}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3D-new}{}}} +\subsection{Method \code{new()}}{ +Creates a new instance of this [R6][R6::R6Class] class. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3D$new( + grid, + zmat, + plot_lab = NULL, + x1_lab = "x1", + x2_lab = "x2", + z_lab = "z" +)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{grid}}{(`list()`)\cr +List with the `x1` and `x2` grid.} + +\item{\code{zmat}}{(`matrix()`)\cr +The result of evaluation at each element of the cross product of `grid$x1` and `grid$x2`.} + +\item{\code{plot_lab}}{(`character(1)`)\cr +Label of the plot.} + +\item{\code{x1_lab}}{(`character(1)`)\cr +Label of the x1 axis.} + +\item{\code{x2_lab}}{(`character(1)`)\cr +Label of the x2 axis.} + +\item{\code{z_lab}}{(`character(1)`)\cr +Label of the z axis.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3D-init_layer_contour}{}}} +\subsection{Method \code{init_layer_contour()}}{ +Initialize the plot with contour lines. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3D$init_layer_contour( + opacity = 0.8, + colorscale = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), + show_title = TRUE, + ... +)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{opacity}}{(`numeric(1)`)\cr +Opacity of the layer.} + +\item{\code{colorscale}}{(`list()`)\cr +The coloring of the contour.} + +\item{\code{show_title}}{(`logical(1)`)\cr +Indicator whether to show the title of the plot.} + +\item{\code{...}}{(`any`)\cr +Further arguments passed to `add_trace(...)`.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3D-init_layer_surface}{}}} +\subsection{Method \code{init_layer_surface()}}{ +Initialize the plot as 3D surface. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3D$init_layer_surface( + opacity = 0.8, + colorscale = list(c(0, 1), c("rgb(176,196,222)", "rgb(160,82,45)")), + show_contours = FALSE, + show_title = TRUE, + ... +)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{opacity}}{(`numeric(1)`)\cr +Opacity of the layer.} + +\item{\code{colorscale}}{(`list()`)\cr +The coloring of the surface.} + +\item{\code{show_contours}}{(`logical(1)`)\cr +Indicator whether to show the contours of the surface.} + +\item{\code{show_title}}{(`logical(1)`)\cr +Indicator whether to show the title of the plot.} + +\item{\code{...}}{(`any`)\cr +Further arguments passed to `add_trace(...)`.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3D-set_layout}{}}} +\subsection{Method \code{set_layout()}}{ +Set the layout of the plotly plot. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3D$set_layout(...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{...}}{Layout options directly passed to `layout(...)`.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3D-set_scene}{}}} +\subsection{Method \code{set_scene()}}{ +Set the view for a 3D plot. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3D$set_scene(x, y, z)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{x}}{(`numeric(1)`) The view from which the "camera looks down" to the plot.} + +\item{\code{y}}{(`numeric(1)`) The view from which the "camera looks down" to the plot.} + +\item{\code{z}}{(`numeric(1)`) The view from which the "camera looks down" to the plot.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3D-plot}{}}} +\subsection{Method \code{plot()}}{ +Return the plot and hence plot it or do further processing. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3D$plot()}\if{html}{\out{
}} +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3D-save}{}}} +\subsection{Method \code{save()}}{ +Save the plot by using plotlys `save_image()` function. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3D$save(...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{...}}{Further arguments passed to `save_image()`.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3D-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3D$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/Visualizer3DModel.Rd b/man/Visualizer3DModel.Rd new file mode 100644 index 0000000..ae4a155 --- /dev/null +++ b/man/Visualizer3DModel.Rd @@ -0,0 +1,148 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Visualizer3DModel.R +\name{Visualizer3DModel} +\alias{Visualizer3DModel} +\title{Visualize Model} +\description{ +This class is used to create 3D visualizations of learners and tasks. +} +\section{Super class}{ +\code{vistool::Visualizer3D} -> \code{Visualizer3DModel} +} +\section{Public fields}{ +\if{html}{\out{
}} +\describe{ +\item{\code{task}}{(`mlr3::Task`)\cr +Task used to train the model.} + +\item{\code{learner}}{(`mlr3::Learner`)\cr +Learner used to train the model.} +} +\if{html}{\out{
}} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-Visualizer3DModel-new}{\code{Visualizer3DModel$new()}} +\item \href{#method-Visualizer3DModel-add_training_data}{\code{Visualizer3DModel$add_training_data()}} +\item \href{#method-Visualizer3DModel-add_decision_boundary}{\code{Visualizer3DModel$add_decision_boundary()}} +\item \href{#method-Visualizer3DModel-clone}{\code{Visualizer3DModel$clone()}} +} +} +\if{html}{\out{ +
Inherited methods + +
+}} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3DModel-new}{}}} +\subsection{Method \code{new()}}{ +Creates a new instance of this [R6][R6::R6Class] class. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3DModel$new( + task, + learner, + x1_limits = NULL, + x2_limits = NULL, + padding = 0, + n_points = 100L +)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{task}}{([mlr3::Task])\cr +The task to train the model on.} + +\item{\code{learner}}{([mlr3::Learner])\cr +The learner to train the model with.} + +\item{\code{x1_limits}}{(`numeric(2)`)\cr +The x1 limits.} + +\item{\code{x2_limits}}{(`numeric(2)`)\cr +The x2 limits.} + +\item{\code{padding}}{(`numeric(1)`)\cr +A margin that is added to x1limits and x2limits. +The x1 margin is calculated by `max(x1lmits) - min(x1limits) * padding`.} + +\item{\code{n_points}}{(`integer(1)`)\cr +The number of generated point per dimension. +Note that a grid of `npoints^2` values is generated and evaluated by `objective$eval(x)` to plot the surface.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3DModel-add_training_data}{}}} +\subsection{Method \code{add_training_data()}}{ +Adds the training data to the plot. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3DModel$add_training_data(size = 5, color = "grey", ...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{size}}{(`numeric(1)`)\cr +Size of the points.} + +\item{\code{color}}{(`character(1)`)\cr +Color of the points.} + +\item{\code{...}}{(`any`)\cr +Further arguments passed to `add_trace(...)`.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3DModel-add_decision_boundary}{}}} +\subsection{Method \code{add_decision_boundary()}}{ +Adds the decision boundary to the plot. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3DModel$add_decision_boundary(threshold = 0.5, ...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{threshold}}{(`numeric(1)`)\cr +Threshold for the decision boundary.} + +\item{\code{...}}{(`any`)\cr +Further arguments passed to `add_trace(...)`.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3DModel-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3DModel$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/Visualizer3DObjective.Rd b/man/Visualizer3DObjective.Rd new file mode 100644 index 0000000..38094b5 --- /dev/null +++ b/man/Visualizer3DObjective.Rd @@ -0,0 +1,289 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Visualizer3DObj.R +\name{Visualizer3DObjective} +\alias{Visualizer3DObjective} +\title{Visualize Objective} +\description{ +This class is used to create visualizations and animations of optimization traces. +} +\section{Super class}{ +\code{vistool::Visualizer3D} -> \code{Visualizer3DObjective} +} +\section{Public fields}{ +\if{html}{\out{
}} +\describe{ +\item{\code{objective}}{(`Objective`)\cr +The objective which was optimized. +This object is used to generate the surface/contour lines.} +} +\if{html}{\out{
}} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-Visualizer3DObjective-new}{\code{Visualizer3DObjective$new()}} +\item \href{#method-Visualizer3DObjective-add_optimization_trace}{\code{Visualizer3DObjective$add_optimization_trace()}} +\item \href{#method-Visualizer3DObjective-add_layer_taylor}{\code{Visualizer3DObjective$add_layer_taylor()}} +\item \href{#method-Visualizer3DObjective-add_layer_hessian}{\code{Visualizer3DObjective$add_layer_hessian()}} +\item \href{#method-Visualizer3DObjective-animate}{\code{Visualizer3DObjective$animate()}} +\item \href{#method-Visualizer3DObjective-clone}{\code{Visualizer3DObjective$clone()}} +} +} +\if{html}{\out{ +
Inherited methods + +
+}} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3DObjective-new}{}}} +\subsection{Method \code{new()}}{ +Creates a new instance of this [R6][R6::R6Class] class. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3DObjective$new( + objective, + x1_limits = NULL, + x2_limits = NULL, + padding = 0, + n_points = 100L +)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{objective}}{(`Objective`)\cr +The objective which was optimized. +This object is used to generate the surface/contour lines.} + +\item{\code{x1_limits}}{(`numeric(2)`)\cr +The x1 limits.} + +\item{\code{x2_limits}}{(`numeric(2)`)\cr +The x2 limits.} + +\item{\code{padding}}{(`numeric(1)`)\cr +A margin that is added to x1limits and x2limits. +The x1 margin is calculated by `max(x1lmits) - min(x1limits) * padding`.} + +\item{\code{n_points}}{(`integer(1)`)\cr +The number of generated point per dimension. +Note that a grid of `npoints^2` values is generated and evaluated by `objective$eval(x)` to plot the surface.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3DObjective-add_optimization_trace}{}}} +\subsection{Method \code{add_optimization_trace()}}{ +Add an optimization trace. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3DObjective$add_optimization_trace( + opt, + line_color = colSampler(), + mcolor_out = "black", + npoints = NULL, + npmax = NULL, + name = NULL, + offset = NULL, + add_marker_at = 1, + marker_shape = "circle", + marker_color = NULL, + ... +)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{opt}}{(`Optimizer`)\cr +The optimizer from which the archive is extracted and used to plot the trace.} + +\item{\code{line_color}}{(`character(1)`)\cr +The color of the trace.} + +\item{\code{mcolor_out}}{(`character(1)`)\cr +The outer line color of the marker.} + +\item{\code{npoints}}{(`integer(1)`)\cr +The number of used points from the archive. +Default is `NULL` which means that all points are used. +If set, a sequence from 1 to `nrow(opt$archive)` is created.} + +\item{\code{npmax}}{(`integer(1)`)\cr +The number of points used from the sequence `seq_len(nrow(opt$archive))[seq_len(npmax)]`} + +\item{\code{name}}{(`character(1)`)\cr +The name of the trace in the legend. +Default is `NULL` which means that the name is pasted from `opt$id` and `objective$id`.} + +\item{\code{offset}}{(`numeric(3)`)\cr +Trace shift in direction (x, y, z).} + +\item{\code{add_marker_at}}{(`integer()`)\cr +Vector of iterations at which a marker is added.} + +\item{\code{marker_shape}}{(`character()`)\cr +Vector indicating the shape of the markers. +If `length(marker_shape) == 1`, all markers get the same shape. +The other option is to specify all markers individually by passing a vector of `length(add_marker_at)`. +For a list of all shapes see `schema(F)$traces$XXX$attributes$marker$symbol$values` with `XXX` one of `scatter` or `scatter3d`. +If `marker_shape = NA`, no marker are added.} + +\item{\code{marker_color}}{(`character()`)\cr +The colors for the markers.} + +\item{\code{...}}{Further arguments passed to `add_trace(...)`.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3DObjective-add_layer_taylor}{}}} +\subsection{Method \code{add_layer_taylor()}}{ +Add a Taylor approximation (for 1 and 2 degrees). +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3DObjective$add_layer_taylor( + x0, + degree = 2, + x1margin = 0, + x2margin = 0, + npoints_per_dim = 20L, + zlim = NULL, + ... +)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{x0}}{(`numeric()) `\cr +The point around which the approximation is done.} + +\item{\code{degree}}{(`integer(1)`)\cr +The degree of the approximation (only 1 and 2 is implemented).} + +\item{\code{x1margin}}{(`numeric(1)`)\cr +The "length" of the hyperplane in direction x1.} + +\item{\code{x2margin}}{(`numeric(1)`)\cr +The "length" of the hyperplane in direction x2.} + +\item{\code{npoints_per_dim}}{(`integer(1)`)\cr +Number of points per dimension for the plotting grid.} + +\item{\code{zlim}}{(`numeric(2)`)\cr +The limits for z. +Can be helpful if the hyperplane as a huge z range and therefore the plot looks ugly.} + +\item{\code{...}}{(`any`)\cr +Additional parameter passed to `add_surface()`.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3DObjective-add_layer_hessian}{}}} +\subsection{Method \code{add_layer_hessian()}}{ +Add two "arrows" as eigenvectors of the Hessian. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3DObjective$add_layer_hessian( + x0, + x1length = 0.1, + x2length = 0.1, + ... +)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{x0}}{(`numeric(2)`)\cr +The point at which the Hessian is calculated.} + +\item{\code{x1length}}{(`numeric(1)`)\cr +The length of the first eigenvector.} + +\item{\code{x2length}}{(`numeric(1)`)\cr +The length of the second eigenvector.} + +\item{\code{...}}{(`any`)\cr +Additional arguments passed to `add_trace`.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3DObjective-animate}{}}} +\subsection{Method \code{animate()}}{ +Create an animation of `$plot()`. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3DObjective$animate( + dir = "animation", + nframes = 10L, + view_start = list(x = 1, y = 1, z = 1), + view_end = list(x = 1, y = 1, z = 1), + fext = "png", + stops = NULL, + ... +)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{dir}}{(`character(1)`)\cr +The directory in which all the images are saved.} + +\item{\code{nframes}}{(`integer(1)`)\cr +The number of frames.} + +\item{\code{view_start}}{(`list()`)\cr +The start view of the animation.} + +\item{\code{view_end}}{(`list()`)\cr +The end view of the animation.} + +\item{\code{fext}}{(`character(1)`)\cr +The file extension (default is `png`).} + +\item{\code{stops}}{(`integer()`)\cr +The step / iteration in the archives of the optimizers added by `$addLayerOptimizationTrace()` at which a frame is taken. +Must have exact the same length as defined in `nframes`. +By default, a sequence with equidistant points is generated for `stops`.} + +\item{\code{...}}{(`any`)\cr +Additional arguments passed to `$save(...)`.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-Visualizer3DObjective-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{Visualizer3DObjective$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/colSampler.Rd b/man/colSampler.Rd index 6111500..ba1dba9 100644 --- a/man/colSampler.Rd +++ b/man/colSampler.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Visualizer2D.R +% Please edit documentation in R/Visualizer3D.R \name{colSampler} \alias{colSampler} \title{Randomly generate colors} diff --git a/tests/testthat/test-Visualizer1DModel.R b/tests/testthat/test-Visualizer1DModel.R new file mode 100644 index 0000000..4fd92a9 --- /dev/null +++ b/tests/testthat/test-Visualizer1DModel.R @@ -0,0 +1,25 @@ +test_that("1D Model with regression task works", { + require_namespaces("mlr3learners") + + task = tsk("mtcars") + task$select("gear") + + learner = lrn("regr.svm") + + vis = Visualizer1DModel$new(task, learner) + + vis$plot() +}) + +test_that("1D Model with regression task and trainings data works", { + require_namespaces("mlr3learners") + + task = tsk("mtcars") + task$select("gear") + + learner = lrn("regr.svm") + + vis = Visualizer1DModel$new(task, learner, training_points = TRUE) + + vis$plot() +}) diff --git a/tests/testthat/test-Visualizer2DModel.R b/tests/testthat/test-Visualizer2DModel.R index af2f725..c69cc79 100644 --- a/tests/testthat/test-Visualizer2DModel.R +++ b/tests/testthat/test-Visualizer2DModel.R @@ -1,4 +1,4 @@ -test_that("multiplication works", { +test_that("2D Model with regression task works", { require_namespaces("mlr3learners") task = tsk("mtcars") @@ -11,7 +11,7 @@ test_that("multiplication works", { vis$plot() }) -test_that("multiplication works", { +test_that("2D model with regression task and training points works", { require_namespaces("mlr3learners") task = tsk("mtcars") @@ -19,12 +19,12 @@ test_that("multiplication works", { learner = lrn("regr.svm") - vis = Visualizer2DModel$new(task, learner) + vis = Visualizer2DModel$new(task, learner, training_points = TRUE) - vis$plot(training_data = TRUE) + vis$plot() }) -test_that("multiplication works", { +test_that("2D model with classification task works", { require_namespaces("mlr3learners") task = tsk("spam") @@ -35,5 +35,18 @@ test_that("multiplication works", { vis = Visualizer2DModel$new(task, learner) vis$plot() - vis$plot(training_data = TRUE) +}) + + +test_that("2D model with classification task and training points works", { + require_namespaces("mlr3learners") + + task = tsk("spam") + task$select(c("you", "credit")) + + learner = lrn("classif.svm", predict_type = "prob") + + vis = Visualizer2DModel$new(task, learner, training_points = TRUE) + + vis$plot() }) diff --git a/tests/testthat/test-Visualizer2DObj.R b/tests/testthat/test-Visualizer2DObj.R index bdadb50..36a5503 100644 --- a/tests/testthat/test-Visualizer2DObj.R +++ b/tests/testthat/test-Visualizer2DObj.R @@ -1,4 +1,4 @@ -test_that("multiplication works", { +test_that("2D Objective works", { require_namespaces("mlr3learners") obj_branin = obj("TF_branin") @@ -7,3 +7,4 @@ test_that("multiplication works", { vis$plot() }) +