File: interactive.R

package info (click to toggle)
r-cran-eaf 2.5.2-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,016 kB
  • sloc: ansic: 7,281; perl: 848; makefile: 73; sh: 43; python: 27
file content (182 lines) | stat: -rw-r--r-- 6,887 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#' Interactively choose according to empirical attainment function differences 
#' 
#' Creates the same plot as [eafdiffplot()] but waits for the user to click in
#' one of the sides. Then it returns the rectangles the give the differences in
#' favour of the chosen side. These rectangles may be used for interactive
#' decision-making as shown in \citet{DiaLop2020ejor}. The function
#' [choose_eafdiff()] may be used in a non-interactive context.
#' 
#' @param data.left,data.right Data frames corresponding to the input data of
#'   left and right sides, respectively. Each data frame has at least three
#'   columns, the third one being the set of each point. See also
#'   [read_datasets()].
#' 
#' @param intervals (`integer(1)`|`character()`) \cr The absolute range of the
#'   differences \eqn{[0, 1]} is partitioned into the number of intervals
#'   provided. If an integer is provided, then labels for each interval are
#'   computed automatically. If a character vector is provided, its length is
#'   taken as the number of intervals.
#' 
#' @template arg_maximise
#'
#' @param title.left,title.right Title for left and right panels, respectively.
#'  
#' @param ... Other graphical parameters are passed down to
#'   [eafdiffplot()].
#' 
#' 
#' @return `matrix` where the first 4 columns give the coordinates of two
#'   corners of each rectangle and the last column. In both cases, the last
#'   column gives the positive differences in favor of the chosen side.
#' 
#' @seealso    [read_datasets()], [eafdiffplot()], [whv_rect()]
#' 
#' @examples
#'
#' \donttest{
#' extdata_dir <- system.file(package="eaf", "extdata") 
#' A1 <- read_datasets(file.path(extdata_dir, "wrots_l100w10_dat"))
#' A2 <- read_datasets(file.path(extdata_dir, "wrots_l10w100_dat"))
#' if (interactive()) {
#'   rectangles <- choose_eafdiffplot(A1, A2, intervals = 5)
#' } else { # Choose A1
#'   rectangles <- eafdiff(A1, A2, intervals = 5, rectangles = TRUE)
#'   rectangles <- choose_eafdiff(rectangles, left = TRUE)
#' }
#' reference <- c(max(A1[, 1], A2[, 1]), max(A1[, 2], A2[, 2]))
#' x <- split.data.frame(A1[,1:2], A1[,3])
#' hv_A1 <- sapply(split.data.frame(A1[, 1:2], A1[, 3]),
#'                  hypervolume, reference=reference)
#' hv_A2 <- sapply(split.data.frame(A2[, 1:2], A2[, 3]),
#'                  hypervolume, reference=reference)
#' boxplot(list(A1=hv_A1, A2=hv_A2), main = "Hypervolume")
#'
#' whv_A1 <- sapply(split.data.frame(A1[, 1:2], A1[, 3]),
#'                  whv_rect, rectangles=rectangles, reference=reference)
#' whv_A2 <- sapply(split.data.frame(A2[, 1:2], A2[, 3]),
#'                  whv_rect, rectangles=rectangles, reference=reference)
#' boxplot(list(A1=whv_A1, A2=whv_A2), main = "Weighted hypervolume")
#' }
#'
#'@references
#' \insertAllCited{}
#' @concept visualisation
#' @export
choose_eafdiffplot <- function(data.left, data.right, intervals = 5,
                               maximise = c(FALSE, FALSE),
                               title.left = deparse(substitute(data.left)),
                               title.right = deparse(substitute(data.right)),
                               ...)
{
  op <- options(locatorBell = FALSE)
  on.exit(options(op))
  eafdiffplot(data.left, data.right, title.left= title.left, title.right = title.right,
              intervals = intervals, maximise = maximise, ...)
  # FIXME: Avoid calculating eafdiff twice.
  DIFF <- eafdiff(data.left, data.right, intervals = intervals, maximise = maximise,
                  rectangles = TRUE)

  coord <- grid::grid.locator("npc")
  left <- coord$x[[1]] < 0.5
  if (left) cat("LEFT!\n") else cat("RIGHT!\n")
  choose_eafdiff(DIFF, left=left)
}

#' Identify largest EAF differences
#' 
#' Given a list of datasets, return the indexes of the pair with the largest
#' EAF differences according to the method proposed by \citet{DiaLop2020ejor}.
#' 
#'
#' @param data (`list(1)`) A list of matrices with at least 3 columns
#'
#' @template arg_maximise
#'
#' @param intervals (`integer(1)`) \cr The absolute range of the differences
#'   \eqn{[0, 1]} is partitioned into the number of intervals provided.
#'
#' @template arg_refpoint
#'
#' @template arg_ideal_null
#' 
#' @return  (`list()`) A list with two components `pair` and `value`.
#' 
#'@examples
#' # FIXME: This example is too large, we need a smaller one.
#' files <- c("wrots_l100w10_dat","wrots_l10w100_dat")
#' data <- lapply(files, function(x)
#'                read_datasets(file.path(system.file(package="eaf"),
#'                              "extdata", x)))
#' nadir <- apply(do.call(rbind, data)[,1:2], 2, max)
#' x <- largest_eafdiff(data, reference = nadir)
#' str(x)
#'
#'@references
#' \insertAllCited{}
#' 
#'@concept eaf
#'@export
largest_eafdiff <- function(data, maximise = FALSE, intervals = 5, reference,
                            ideal = NULL)
{
  nobjs <- 2
  maximise <- as.logical(rep_len(maximise, nobjs))
  if (nobjs != 2) stop("Only 2 objectives currently supported")
 
  n <- length(data)
  stopifnot(n > 1)
  best_pair <- NULL
  best_value <- 0
  if (is.null(ideal)) {
    # This should be equivalent to
    # cbind(c(range(data[[1]][,1]),range(data[[2]][,1])),
    #       c(range(data[[1]][,2]),range(data[[2]][,2])))
    data_agg <- t(do.call(cbind, lapply(data, function(x) matrixStats::colRanges(x[,1:nobjs]))))
    ideal <- get_ideal(data_agg, maximise = maximise)
  }
  # Convert to a 1-row matrix
  if (is.null(dim(ideal))) dim(ideal) <- c(1,nobjs)
    
  for (a in 1:(n-1)) {
    for (b in (a+1):n) {
      DIFF <- eafdiff(data[[a]], data[[b]], intervals = intervals,
                      maximise = maximise, rectangles = TRUE)
      # Set color to 1
      a_rectangles <- DIFF[ DIFF[, 5] >= 1L, , drop = FALSE]
      a_rectangles[, ncol(a_rectangles)] <- 1
      
      a_value <- whv_rect(ideal, a_rectangles, reference, maximise)
      
      b_rectangles <- DIFF[ DIFF[, 5] <= -1L, , drop = FALSE]
      b_rectangles[, ncol(b_rectangles)] <- 1
      b_value <- whv_rect(ideal, b_rectangles, reference, maximise)
      value <- min(a_value, b_value)
      if (value > best_value) {
        best_value <- value
        best_pair <- c(a, b)
      }
    }
  }
  list(pair=best_pair, value = best_value)
}


#' @param x (`matrix()`) Matrix of rectangles representing EAF differences
#'   (returned by [eafdiff()] with `rectangles=TRUE`).
#' 
#' @param left (`logical(1)`) With `left=TRUE` return the rectangles with
#'   positive differences, otherwise return those with negative differences but
#'   differences are converted to positive.
#' 
#' @rdname choose_eafdiffplot
#'@concept eaf
#'@export
choose_eafdiff <- function(x, left = stop("'left' must be either TRUE or FALSE"))
{
  if (left) return (x[ x[, ncol(x)] > 0L, , drop = FALSE])
  x <- x[ x[, ncol(x)] < 0L, , drop = FALSE]
  # We always return positive colors.
  x[, ncol(x)] <- abs(x[, ncol(x)])
  x
}