Movatterモバイル変換


[0]ホーム

URL:


splot coverage - 67.78%

1
#' splot colors
2
#'
3
#' Get a prespecified set of 9 colors, or a set of graded or random, potentially grouped colors.
4
#' @param x dictates the number and shade of colors. If a single value, returns that many samples of the
5
#'   first \code{seed} entry. If a vector, returns a color for each entry. If numeric, a single seed color
6
#'   is sampled in order of the vector. If a character or factor, a separate seed color is assigned to
7
#'   each level, then sampled within levels. Values or vectors in a list are each assigned a seed color.
8
#' @param by a vector to group \code{x} by; each level is assigned a seed color.
9
#' @param seed a vector of color names or codes to adjust from, lining up with levels of \code{x} or
10
#'   \code{by}, or the name of a palette, partially matching \code{'bright'}, \code{'dark'},
11
#'   \code{'pastel'}, or \code{'grey'}.
12
#' @param brightness adjusts the RGB values of the seed color, usually between -1 and 1.
13
#' @param luminance adjusts the white levels of the seed color, usually between -1 and 1.
14
#' @param opacity sets the opacity of the seed color, between 0 and 1.
15
#' @param extend if \code{method='scale'}, extends the range of the gradient beyond the sampled range,
16
#'   making for more similar colors (defaults is .5, with 0 sampling the full range). If
17
#'   \code{method='related'}, increases the amount any of the RGB values can be adjusted, making for
18
#'   potentially more different colors (default is 2).
19
#' @param lighten logical; if \code{TRUE}, scaled colors are lightened instead of darkened. Only
20
#'   applicable if \code{method='scale'}.
21
#' @param shuffle logical; if \code{TRUE}, scaled colors are shuffled. Only applicable if
22
#'   \code{method='scale'}.
23
#' @param flat logical; if \code{FALSE} and \code{x} is a character, factor, or list, or \code{by} is not
24
#'   missing, a list is returned.
25
#' @param method a character setting the sampling method: If \code{'related'} (\code{'^rel|^ran|^o'}),
26
#'   RGB values are freely adjusted, resulting in similar colors. If \code{'none'} (\code{'^no|^f|^bin'}),
27
#'   Seed colors are simply repeated in each level (sampling is off). Otherwise, RGB values are adjusted
28
#'   together, resulting in a gradient.
29
#' @param grade logical; if \code{TRUE}, seeds are adjusted on the scale of numeric \code{x}s.
30
#'   Otherwise, seeds are adjusted in even steps along numeric \code{x}s.
31
#' @param decreasing logical; if \code{FALSE}, assigns colors to numeric \code{x}s in increasing order.
32
#' @param nas value to replace missing values with.
33
#' @return A character vector of color codes, or a list of such vectors if \code{flat} if \code{FALSE}.
34
#' @details
35
#' If \code{x} and \code{by} are not specified (or are characters with a length of 1, in which case they
36
#' are treated as \code{seed}), only the seed palette is returned.
37
#'
38
#' To expand on a palette, seed colors are assigned to groups, and variants of each seed are assigned to
39
#' values or levels within groups, or randomly or as a gradient if there are no values or level to assign to.
40
#'
41
#' Seed colors are assigned to groups. If \code{x} is a character or factor and no \code{by} has been
42
#' specified, groups are the unique levels of \code{x}. If \code{by} is specified and is a character or
43
#' factor, or has fewer than 10 unique levels, groups are levels of \code{by}. If \code{x} is a list,
44
#' groups are list entries.
45
#'
46
#' The number of variants for each seed color is determined either by a value (if the value has a length
47
#' of 1; e.g., \code{x=10}), the vector's length (if \code{x} is numeric), or the count of the given level
48
#' (if \code{x} is a factor or character vector).
49
#'
50
#' @examples
51
#' # including no arguments or just a palette name will only return
52
#' # the palette as a character vector
53
#' pastel_palette <- splot.color()
54
#' dark_palette <- splot.color("dark")
55
#'
56
#' # entering a number for x will generate that many variants of the first seed color
57
#' red_scale <- splot.color(10, "red")
58
#'
59
#' # entering a list of values as x will return that many variants of the associated seed
60
#' red_and_green_scales <- splot.color(list(10, 10), seed = c("red", "green"))
61
#'
62
#' # this shows gradients of each color in the default palette
63
#' # a list entered as colorby is treated as arguments to splot.color
64
#' # periods before the position name refer to the internally assembled data
65
#' splot(
66
#'   rep(splot.color(), each = 100) ~ rep.int(seq.int(.01, 1, .01), 9),
67
#'   colorby = list(.x, .y),
68
#'   lines = FALSE, mar = c(2, 4, 0, 0), cex = c(points = 3), leg = FALSE, pch = 15,
69
#'   title = "'pastel' palette", labx = "value of x", laby = "seed color"
70
#' )
71
#'
72
#' # colors graded by value, entered in a list
73
#' plot(
74
#'   1:30, numeric(30),
75
#'   pch = 15, cex = 10,
76
#'   col = splot.color(list(1:8, c(7:1, 1:7), 8:1))
77
#' )
78
#'
79
#' # comparing sampling methods:
80
#' #   on top are 1000 similar colors, with different RGB ratios
81
#' #   on bottom are 268 colors with the same RGB ratio at different levels
82
#' splot(
83
#'   c(rnorm(1000), rnorm(1000, 10)) ~ rnorm(2000),
84
#'   lines = FALSE,
85
#'   colors = c(splot.color(1000), splot.color(1000, method = "related"))
86
#' )
87
#'
88
#' @export
89
90
splot.color <- function(
91
    x = NULL, by = NULL, seed = "pastel", brightness = 0, luminance = 0, opacity = 1, extend = .7,
92
    lighten = FALSE, shuffle = FALSE, flat = TRUE, method = "scale", grade = FALSE, decreasing = FALSE, nas = "#000000") {
9344x
  sets <- list(
9444x
    bright = c("#45FF00", "#BA00FF", "#000000", "#FF0000", "#FFFD00", "#003DFF", "#00F2F8", "#999999", "#FF891B"),
9544x
    dark = c("#1B8621", "#681686", "#2A2A2A", "#7C0D0D", "#B5BC00", "#241C80", "#1A7E8B", "#666666", "#B06622"),
9644x
    pastel = c("#82C473", "#A378C0", "#616161", "#9F5C61", "#D3D280", "#6970B2", "#78C4C2", "#454744", "#D98C82"),
9744x
    grey = function(n) grey(.2:n / (n + n * if (n < 10) .1 else .3))
98
  )
9944x
  if (missing(seed) && is.character(x) && (length(x) == 1 || all(tolower(x) %in% colors()))) {
100!
    seed <- x
101!
    x <- numeric(length(seed)) + 1
102
  }
10344x
  if (missing(seed) && is.character(by) && length(by) == 1) {
104!
    seed <- by
105!
    by <- NULL
106
  }
10744x
  seed <- tolower(seed)
10844x
  ox <- NULL
10944x
  lvs <- function(x) if (is.factor(x)) base::levels(x) else sort(unique(x[!is.na(x)]))
11044x
  cn <- ncol(x)
11144x
  if (!is.null(cn) && !is.na(cn) && cn > 1) {
112!
    if (is.null(by)) by <- x[, 2]
113!
    x <- x[, 1]
114!
  } else if (is.list(x) && length(x) == 1) x <- x[[1]]
11544x
  if (!is.null(by)) {
1162x
    ol <- length(x)
1172x
    if (is.null(x)) {
118!
      x <- by
119!
      by <- NULL
1202x
    } else if (ol != length(by)) {
121!
      if (is.numeric(by) && length(by) == 1 && by < ol) {
122!
        by <- rep_len(seq_len(by), ol)
123
      } else {
124!
        by <- NULL
125!
        warning("splot.color: by was dropped as it is not the same length as x", call. = FALSE)
126
      }
127
    }
128
  }
12944x
  if (!is.null(x) && (!(is.list(x) || is.numeric(x)) || (is.numeric(x) && !is.null(by)))) {
1302x
    if (is.null(by)) {
131!
      ox <- x
132!
      x <- as.list(table(x))[lvs(ox)]
133
    } else {
1342x
      if (is.numeric(by) && length(lvs(by)) > 9) {
135!
        warning("splot.color: only non-numeric bys are accepted", call. = FALSE)
136
      } else {
1372x
        ox <- by <- factor(by, lvs(by))
1382x
        x <- split(x, by)
139
      }
140
    }
141
  }
14244x
  ol <- length(x)
14344x
  if (ol == 1 && is.list(x)) {
144!
    x <- x[[1]]
145!
    ol <- length(x)
146!
    ox <- NULL
147
  }
14844x
  n <- if (ol == 1) x else ol
14944x
  if (length(seed) == 1 && grepl("^bri|^dar|^pas|^gr[ae]y", seed)) {
15041x
    seed <- match.arg(seed, names(sets))
15141x
    seed <- if (seed == "grey") {
15212x
      if (n == 1) {
15312x
        "#666666"
154!
      } else if (ol == 1) {
155!
        return(sets$grey(n))
156
      } else {
157!
        sets$grey(n)
158
      }
159
    } else {
16029x
      sets[[seed]]
161
    }
16241x
    if (is.null(x) || (ol == 1 && n < 2)) {
16333x
      return(seed)
164
    }
165
  }
16611x
  ckno <- grepl("^no|^f|^bin", method, TRUE)
16711x
  sc <- if (grepl("^rel|^ran|^o", method, TRUE)) {
1681x
    r <- if (missing(extend)) 2 else max(.001, extend)
1691x
    function(cc, n) {
1701x
      cc <- adjustcolor(cc)
1711x
      hdc <- c(0:9, LETTERS[1:6])
1721x
      hdc <- outer(hdc, hdc, paste0)
1731x
      ccord <- function(cc) {
1741x
        cc <- strsplit(cc, "")[[1]][2:7]
1751x
        cc <- paste0(cc[c(TRUE, FALSE)], cc[c(FALSE, TRUE)])
1761x
        vapply(cc, function(c) which(hdc == c, TRUE), c(0, 0))
177
      }
1781x
      ccode <- function(m) {
1795x
        s <- seq_len(16)
1805x
        paste0("#", paste(apply(m, 2, function(cc) {
18115x
          hdc[which.min(abs(s - cc[1])), which.min(abs(s - cc[2]))]
1825x
        }), collapse = ""))
183
      }
1841x
      csamp <- function(code, n) {
1851x
        n <- max(1, n - 1)
1861x
        ocs <- NULL
1871x
        code <- ccord(code)
188!
        if (any(ck <- code > 14)) code[ck] <- code[ck] - (code[ck] - 14)
189!
        if (any(ck <- code < 2)) code[ck] <- code[ck] + (2 - code[ck])
1901x
        i <- 1
1911x
        while (length(ocs) <= n && i < 9999) {
1925x
          s <- sample(1:6, 3)
1935x
          nc <- code
1945x
          nc[s] <- nc[s] + sample(-r:r, 3, TRUE)
1955x
          nc <- ccode(nc)
1965x
          if (!nc %in% ocs) ocs <- c(ocs, nc)
1975x
          i <- i + 1
198
        }
1991x
        if (any(opacity != 1, brightness != 0, luminance != 0)) {
200!
          adj <- 1 + brightness
201!
          ocs <- adjustcolor(ocs, opacity, adj, adj, adj, c(rep(luminance, 3), 0))
202
        }
203!
        if (length(ocs) != n + 1) ocs <- rep_len(ocs, n + 1)
2041x
        ocs
205
      }
2061x
      csamp(cc, n)
207
    }
20811x
  } else if (ckno) {
2091x
    function(cc, n) {
210!
      ns <- length(n)
211!
      vapply(seq_len(ns), function(i) {
212!
        adj <- ns / (ns + i - 1) + brightness
213!
        if (lighten) adj <- 1.8 - adj
214!
        adjustcolor(cc, opacity, adj, adj, adj, c(rep(luminance, 3), 0))
215
      }, "")
216
    }
217
  } else {
2189x
    function(cc, n) {
2197x
      s <- abs(n - max(n, na.rm = TRUE))
2207x
      n <- length(s)
2217x
      s <- s / max(s, na.rm = TRUE) * (n - 1) + 1
2227x
      r <- max(n, n + n * extend)
2237x
      if (!lighten) s <- s + r - max(s, na.rm = TRUE)
2247x
      vapply(s, function(i) {
2253226x
        adj <- i / r + brightness
226!
        if (lighten) adj <- adj + 1
2273226x
        adjustcolor(cc, opacity, adj, adj, adj, c(rep(luminance, 3), 0))
228
      }, "")
229
    }
230
  }
23111x
  asc <- function(v, si) {
23214x
    n <- length(v)
23314x
    if (is.numeric(v)) v <- round(v, 3)
23410x
    if (!is.numeric(v) || (n != 1 && !grade)) v <- as.numeric(factor(v, lvs(v)))
2352x
    if (!ckno) if (n == 1) v <- seq_len(max(1, v)) else if (length(lvs(v)) == 1) v <- seq_along(v)
23614x
    n <- length(v)
23714x
    l <- lvs(v)
23814x
    u <- sort(unique(v), decreasing)
23914x
    nu <- length(u)
24014x
    pr <- rep(nas, n)
24114x
    cols <- if (nu < 2 && (!length(u) || u < 2)) si else sc(si, u)
24214x
    v <- factor(v[is.finite(v)], u)
2434x
    if (n != nu) cols <- rep(cols, tabulate(v))
24413x
    if (shuffle) sample(cols) else cols[order(order(v, decreasing = decreasing))]
245
  }
24611x
  if (!is.list(x)) {
2478x
    seed <- asc(x, seed[1])
248
  } else {
249!
    if (length(seed) < n) seed <- rep_len(seed, n)
2503x
    seed <- lapply(seq_len(n), function(i) asc(x[[i]], seed[i]))
2513x
    names(seed) <- if (!is.null(names(x))) names(x) else vapply(seed, "[[", "", 1)
2523x
    if (flat) {
2532x
      seed <- if (!is.null(ox) && all(lvs(ox) %in% names(seed))) {
2541x
        by <- as.character(ox)
2551x
        for (g in lvs(ox)) {
2562x
          su <- !is.na(by) & !is.nan(by) & by == g
2572x
          ssu <- sum(su)
2582x
          if (is.finite(ssu) && ssu) by[su] <- rep_len(seed[[g]], ssu)
259
        }
2601x
        by
261
      } else {
2621x
        unlist(seed)
263
      }
264
    }
265
  }
26610x
  if (!is.list(seed)) seed[is.na(seed) | is.nan(seed) | seed %in% c("NA", "NaN", "Inf", "-Inf")] <- nas
26711x
  if (opacity == 1) seed <- if (is.list(seed)) lapply(seed, function(s) sub("FF$", "", s)) else sub("FF$", "", seed)
26811x
  seed
269
}
1
#' Split Plot
2
#'
3
#' A plotting function aimed at automating some common visualization tasks in order to ease data exploration.
4
#' @param y a formula (see note), or the primary variable(s) to be shown on the y axis (unless \code{x} is not specified).
5
#'   When not a formula, this can be one or more variables as objects, or names in \code{data}.
6
#' @param data a \code{data.frame} to pull variables from. If variables aren't found in \code{data}, they will be looked
7
#'   for in the environment.
8
#' @param su a subset to all variables, applied after they are all retrieved from \code{data} or the environment.
9
#' @param type determines the type of plot to make, between \code{"bar"}, \code{"line"}, \code{"density"}, or
10
#'   \code{"scatter"}. If \code{"density"}, \code{x} is ignored. Anything including the first letter of each is accepted
11
#'   (e.g., \code{type='l'}).
12
#' @param split how to split any continuous variables (those with more than \code{lim} levels as factors). Default is
13
#'   \code{"median"}, with \code{"mean"}, \code{"standard deviation"}, \code{"quantile"}, or numbers as options. If
14
#'   numbers, the variable is either cut at each value in a vector, or broken into roughly equal chunks. Entering an
15
#'   integer (e.g., \code{split = 3L}) that is greater than 1 will force splitting into segments. Otherwise variables will
16
#'   be split by value if you enter a single value for split and there are at least two data less than or equal to and
17
#'   greater than the split, or if you enter more than 1 value for split. If a numeric split is not compatible with
18
#'   splitting by value or segment, splitting will default to the median.
19
#' @param levels a list with entries corresponding to variable names, used to rename and/or reorder factor levels. To
20
#'   reorder a factor, enter a vector of either numbers or existing level names in the new order (e.g.,
21
#'   \code{levels =} \code{list(var =} \code{c(3,2,1))}). To rename levels of a factor, enter a character vector the same
22
#'   length as the number of levels. To rename and reorder, enter a list, with names as the first entry, and order as the
23
#'   second entry (e.g., \code{levels =} \code{list(var =} \code{list(c('a','b','c'),} \code{c(3,2,1)))}). This happens
24
#'   after variables are split, so names and orders should correspond to the new split levels of split variables. For
25
#'   example, if a continuous variable is median split, it now has two levels ('Under Median' and 'Over Median'), which are
26
#'   the levels reordering or renaming would apply to. Multiple variables entered as \code{y} can be renamed and sorted
27
#'   with an entry titled \code{'mv'}.
28
#' @param sort specified the order of character or factor \code{x} levels. By default, character or factor \code{x} levels
29
#'   are sorted alphabetically. \code{FALSE} will prevent this (preserving entered order). \code{TRUE} or \code{'d'} will
30
#'   sort by levels of \code{y} in decreasing order, and anything else will sort in increasing order.
31
#' @param error string; sets the type of error bars to show in bar or line plots, or turns them off. If \code{FALSE}, no
32
#'   error bars will be shown. Otherwise, the default is \code{"standard error"} (\code{'^s'}), with \code{"confidence
33
#'   intervals"} (anything else) as an option.
34
#' @param error.color color of the error bars. Default is \code{'#585858'}.
35
#' @param error.lwd line weight of error bars. Default is 2.
36
#' @param lim numeric; checked against the number of factor levels of each variable. Used to decide which variables should
37
#'   be split, which colors to use, and when to turn off the legend. Default is \code{9}. If set over \code{20}, \code{lim}
38
#'   is treated as infinite (set to \code{Inf}).
39
#' @param lines logical or a string specifying the type of lines to be drawn in scatter plots. By default (and whenever
40
#'   \code{cov} is not missing, or if \code{lines} matches \code{'^li|^lm|^st'}), a prediction line is fitted with
41
#'   \code{\link[stats]{lm}}. For (potentially) bendy lines, \code{'loess'} (matching \code{'^loe|^po|^cu'}) will use
42
#'   \code{\link[stats]{loess}}, and \code{'spline'} (\code{'^sm|^sp|^in'}) will use \code{\link[stats]{smooth.spline}}.
43
#'   If \code{y} is not numeric and has only 2 levels, \code{'probability'} (\code{'^pr|^log'}) will draw probabilities
44
#'   estimated by a logistic regression (\code{glm(y ~} \code{x, binomial)}). \code{'connected'} (\code{'^e|^co|^d'}) will
45
#'   draw lines connecting all points, and \code{FALSE} will not draw any lines.
46
#' @param colors sets a color theme or manually specifies colors. Default theme is \code{"pastel"}, with \code{"dark"} and
47
#'   \code{"bright"} as options; these are passed to \code{\link{splot.color}}. If set to \code{"grey"}, or if \code{by}
48
#'   has more than 9 levels, a grey scale is calculated using \code{\link[grDevices]{gray}}. See the \code{col} parameter
49
#'   in \code{\link[graphics]{par}} for acceptable manual inputs. To set text and axis colors, \code{col} sets outside
50
#'   texts (title, sud, labx, laby, and note), \code{col.sub} or \code{col.main} sets the frame titles, and \code{col.axis}
51
#'   sets the axis text and line colors. To set the color of error bars, use \code{error.color}. For histograms, a vector of
52
#'   two colors would apply to the density line and bars separately (e.g., for \code{color =} \code{c('red','green')}, the
53
#'   density line would be red and the histogram bars would be green). See the \code{color.lock} and \code{color.offset}
54
#'   arguments for more color controls.
55
#' @param colorby a variable or list of arguments used to set colors and the legend, alternatively to \code{by}. If
56
#'   \code{by} is not missing, \code{colorby} will be reduced to only the unique combinations of \code{by} and \code{colorby}.
57
#'   For example, if \code{by} is a participant ID with multiple observations per participant, and \code{by} is a condition
58
#'   ID which is the same for all observations from a given participant, \code{colorby} would assign a single color to each
59
#'   participant based on their condition. A list will be treated as a call to \code{\link{splot.color}}, so arguments can be
60
#'   entered positionally or by name. Data entered directly into splot can be accessed by position name preceded by a
61
#'   period. For example, \code{splot(rnorm(100),} \code{colorby=.y)} would draw a histogram, with bars colored by the value
62
#'   of \code{y} (\code{rnorm(100)} in this case).
63
#' @param ... passes additional arguments to \code{\link[graphics]{par}} or \code{\link[graphics]{legend}}. Arguments before
64
#'   this can be named partially; those after must by fully named.
65
#' @param colorby.leg logical; if \code{FALSE}, a legend for \code{colorby} is never drawn. Otherwise, a legend for
66
#'   \code{colorby} will be drawn if there is no specified \code{by}, or for non-scatter plots (overwriting the usual legend).
67
#' @param color.lock logical; if \code{FALSE}, colors will not be adjusted to offset lines from points or histogram bars.
68
#' @param color.offset how much points or histogram bars should be offset from the initial color used for lines. Default is
69
#'   1.1; values greater than 1 lighten, and less than 1 darken.
70
#' @param color.summary specifies the function used to collapse multiple colors for a single display. Either a string
71
#'   matching one of \code{'mean'} (which uses \code{\link{splot.colormean}} to average RGB values), \code{'median'} (
72
#'   which treats codes as ordered, and selects that at the rounded median), or \code{'mode'} (which selects the most
73
#'   common code), or a function which takes color codes in its first argument, and outputs a single color code as a
74
#'   character.
75
#' @param opacity a number between 0 and 1; sets the opacity of points, lines, and bars. Semi-opaque lines will sometimes
76
#'   not be displayed in the plot window, but will show up when the plot is written to a file.
77
#' @param dark logical; if \code{TRUE}, sets text and axis colors to \code{"white"}. Defaults to the \code{splot.dark}
78
#'   option.
79
#' @param x secondary variable, to be shown in on the x axis. If not specified, \code{type} will be set to \code{'density'}.
80
#'   If \code{x} is a factor or vector of characters, or has fewer than \code{lim} levels when treated as a factor,
81
#'   \code{type} will be set to \code{'line'} unless specified.
82
#' @param by the 'splitting' variable within each plot, by which the plotted values of \code{x} and \code{y} will be
83
#'   grouped.
84
#' @param between a single object or name, or two in a vector (e.g., \code{c(b1, b2)}), the levels of which will determine
85
#'   the number of plot windows to be shown at once (the cells in a matrix of plots; levels of the first variable as rows,
86
#'   and levels of the second as columns).
87
#' @param cov additional variables used for adjustment. Bar and line plots include all \code{cov} variables in their
88
#'   regression models (via \code{\link[stats]{lm}}, e.g., \code{lm(y ~ 0 + x + cov1 + cov2)}) as covariates. Scatter plots
89
#'   with lines include all \code{cov} variables in the regression model to adjust the prediction line (e.g.,
90
#'   \code{lm(y ~ x + x^2)}).
91
#'   \code{\link[graphics]{par}} options \code{col}, \code{mfrow}, \code{oma}, \code{mar}, \code{mgp}, \code{font.main},
92
#'   \code{cex.main}, \code{font.lab}, \code{tcl}, \code{pch}, \code{lwd}, and \code{xpd} are all set within the function,
93
#'   but will be overwritten if they are included in the call. For example, \code{col} sets font colors in this case
94
#'   (as opposed to \code{colors} which sets line and point colors). The default is \code{'#303030'} for a nice dark grey,
95
#'   but maybe you want to lighten that up: \code{col='#606060'}. After arguments have been applied to
96
#'   \code{\link[graphics]{par}}, if any have not been used and match a \code{\link[graphics]{legend}} argument, these will
97
#'   be applied to \code{\link[graphics]{legend}}.
98
#' @param line.type a character setting the style of line (e.g., with points at joints) to be drawn in line plots. Default
99
#'   is \code{'b'} if \code{error} is \code{FALSE}, and \code{'l'} otherwise. See the \code{line} argument of
100
#'   \code{\link[graphics]{plot.default}} for options. \code{line.type='c'} can look nice when there aren't a lot of
101
#'   overlapping error bars.
102
#' @param mv.scale determines whether to center and scale multiple \code{y} variables. Does not center or scale by default.
103
#'   Anything other than \code{'none'} will mean center each numeric \code{y} variable. Anything matching \code{'^t|z|sc'}
104
#'   will also scale.
105
#' @param mv.as.x logical; if \code{TRUE}, variable names are displayed on the x axis, and \code{x} is treated as \code{by}.
106
#' @param save logical; if \code{TRUE}, an image of the plot is saved to the current working directory.
107
#' @param format the type of file to save plots as. Default is \code{cairo_pdf}; see
108
#'   \code{\link[grDevices]{Devices}} for options.
109
#' @param dims a vector of 2 values (\code{c(width, height)}) specifying the dimensions of a plot to save in inches or
110
#'   pixels depending on \code{format}. Defaults to the dimensions of the plot window.
111
#' @param file.name a string with the name of the file to be save (excluding the extension, as this is added depending on
112
#'   \code{format}).
113
#' @param myl sets the range of the y axis (\code{ylim} of \code{\link{plot}} or \code{\link[graphics]{barplot}}).
114
#'   If not specified, this will be calculated from the data.
115
#' @param mxl sets the range of the x axis (\code{xlim} of \code{\link{plot}}). If not specified, this will be
116
#'   calculated from the data.
117
#' @param autori logical; if \code{FALSE}, the origin of plotted bars will be set to 0. Otherwise, bars are adjusted such
118
#'   that they extend to the bottom of the y axis.
119
#' @param xlas,ylas numeric; sets the orientation of the x- and y-axis labels. See \code{\link[graphics]{par}}.
120
#' @param xaxis,yaxis logical; if \code{FALSE}, the axis will not be drawn.
121
#' @param breaks determines the width of histogram bars. See \code{\link[graphics]{hist}}.
122
#' @param density.fill logical; \code{FALSE} will turn off polygon fills when they are displayed, \code{TRUE} will replace
123
#'   histograms with polygons.
124
#' @param density.opacity opacity of the density polygons, between 0 and 1.
125
#' @param density.args list of arguments to be passed to \code{\link[stats]{density}}.
126
#' @param leg sets the legend inside or outside the plot frames (when a character matching \code{'^i'}, or a character
127
#'   matching \code{'^o'} or a number respectively), or turns it off (when \code{FALSE}). When inside, a legend is drawn in
128
#'   each plot frame. When outside, a single legend is drawn either to the right of all plot frames, or within an empty
129
#'   plot frame. By default, this will be determined automatically, tending to set legends outside when there are multiple
130
#'   levels of \code{between}. A number will try and set the legend in an empty frame within the grid of plot frames. If
131
#'   there are no empty frames, the legend will just go to the side as if \code{leg='outside'}.
132
#' @param lpos sets the position of the legend within its frame (whether inside or outside of the plot frames) based on
133
#'   keywords (see \code{\link[graphics]{legend}}. By default, when the legend is outside, \code{lpos} is either
134
#'   \code{'right'} when the legend is in a right-hand column, or \code{'center'} when in an empty plot frame. When the
135
#'   legend is inside and \code{lpos} is not specified, the legend will be placed automatically based on the data. Set to
136
#'   \code{'place'} to manually place the legend; clicking the plot frame will set the top left corner of the legend.
137
#' @param lvn level variable name. Logical: if \code{FALSE}, the names of by and between variables will not be shown
138
#'   before their level (e.g., for a sex variable with a "female" level, "sex: female" would become "female" above each
139
#'   plot window).
140
#' @param leg.title sets the title of the legend (which is the by variable name by default), or turns it off with
141
#'   \code{FALSE}.
142
#' @param leg.args a list passing arguments to the \code{\link[graphics]{legend}} call.
143
#' @param title logical or a character: if \code{FALSE}, the main title is turned off. If a character, this will be shown
144
#'   as the main title.
145
#' @param labx,laby logical or a character: if \code{FALSE}, the label on the x axis is turned off. If a character, this
146
#'   will be shown as the axis label.
147
#' @param lty logical or a vector: if \code{FALSE}, lines are always solid. If a vector, changes line type based on each
148
#'   value. Otherwise loops through available line types, see \code{\link[graphics]{par}}.
149
#' @param lwd numeric; sets the weight of lines in line, density, and scatter plots. Default is 2. See
150
#'   \code{\link[graphics]{par}}.
151
#' @param sub affects the small title above each plot showing \code{between} levels; text replaces it, and \code{FALSE}
152
#'   turns it off.
153
#' @param note logical; if \code{FALSE}, the note at the bottom about splits and/or lines or error bars is turned off.
154
#' @param font named numeric vector: \code{c(title,sud,leg,leg.title,note)}. Sets the font of the title, su display, legend
155
#'   levels and title, and note. In addition, \code{font.lab} sets the x and y label font, \code{font.sub} sets the font of
156
#'   the little title in each panel, \code{font.axis} sets the axis label font, and \code{font.main} sets the between level/n
157
#'   heading font; these are passed to \code{\link[graphics]{par}}. See the input section.
158
#' @param cex named numeric vector: \code{c(title,sud,leg,note,points)}. Sets the font size of the title, su display, legend,
159
#'   note, and points. In addition, \code{cex.lab} sets the x and y label size, \code{cex.sub} sets the size of the little
160
#'   title in each panel, \code{cex.axis} sets the axis label size, and \code{cex.main} sets the between level/n heading size;
161
#'   these are passed to \code{\link[graphics]{par}}. See the input section.
162
#' @param sud affects the heading for subset and covariates/line adjustments (su display); text replaces it, and
163
#'   \code{FALSE} turns it off.
164
#' @param ndisp logical; if \code{FALSE}, n per level is no longer displayed in the subheadings.
165
#' @param labels logical; if \code{FALSE}, sets all settable text surrounding the plot to \code{FALSE} (just so you don't
166
#'   have to set all of them if you want a clean frame).
167
#' @param labels.filter a regular expression string to be replaced in label texts with a blank space. Default is
168
#'   \code{'_'}, so underscores appearing in the text of labels are replace with blank spaces. Set to
169
#'   \code{FALSE} to prevent all filtering.
170
#' @param labels.trim numeric or logical; the maximum length of label texts (in number of characters). Default is 20, with
171
#'   any longer labels being trimmed. Set to \code{FALSE} to prevent any trimming.
172
#' @param points logical; if \code{FALSE}, the points in a scatter plot are no longer drawn.
173
#' @param points.first logical; if \code{FALSE}, points are plotted after lines are drawn in a scatter plot, placing lines
174
#'   behind points. This does not apply to points or lines added in \code{add}, as that is always evaluated after the main
175
#'   points and lines are drawn.
176
#' @param byx logical; if \code{TRUE} (default) and \code{by} is specified, regressions for bar or line plots compare
177
#'   levels of \code{by} for each level of \code{x}. This makes for more intuitive error bars when comparing levels of
178
#'   \code{by} within a level of \code{x}; otherwise, the model is comparing the difference between the first level of
179
#'   \code{x} and each of its other levels.
180
#' @param drop named logical vector: \code{c(x,by,bet)}. Specifies how levels with no data should be treated. All are
181
#'   \code{TRUE} by default, meaning only levels with data will be presented, and the layout of \code{between} levels
182
#'   will be minimized. \code{x} only applies to bar or line plots. \code{by} relates to levels presented in the legend.
183
#'   If \code{bet} is \code{FALSE}, the layout of \code{between} variables will be strict, with levels of \code{between[1]}
184
#'   as rows, and levels of \code{between[2]} as columns -- if there are no data at an intersection of levels, the
185
#'   corresponding panel will be blank. See the input section.
186
#' @param prat panel ratio, referring to the ratio between plot frames and the legend frame when the legend is out. A
187
#'   single number will make all panels of equal width. A vector of two numbers will adjust the ratio between plot panels
188
#'   and the legend panel. For example, \code{prat=c(3,1)} makes all plot panels a relative width of 3, and the legend frame
189
#'   a relative width of 1.
190
#' @param check.height logical; if \code{FALSE}, the height of the plot frame will not be checked before plotting is
191
#'   attempted. The check tries to avoid later errors, but may prevent plotting when a plot is possible.
192
#' @param model logical; if \code{TRUE}, the summary of an interaction model will be printed. This model won't always align
193
#'   with what is plotted since variables may be treated differently, particularly in the case of interactions.
194
#' @param options a list with named arguments, useful for setting temporary defaults if you plan on using some of the same
195
#'   options for multiple plots (e.g., \code{opt = list(}\code{type = 'bar',} \code{colors = 'grey',}
196
#'   \code{bg = '#999999');} \code{splot(x ~ y,} \code{options = opt)}).
197
#'   use \code{\link{quote}} to include options that are to be evaluated within the function (e.g.,
198
#'   \code{opt =} \code{list(su =} \code{quote(y > 0))}).
199
#' @param add evaluated within the function, so you can refer to the objects that are returned, to variable names (those
200
#'   from an entered data frame or entered as arguments), or entered data by their position, preceded by '.' (e.g.,
201
#'   \code{mod =} \code{lm(.y~.x)}). Useful for adding things like lines to a plot while the parameters are still
202
#'   those set by the function (e.g., \code{add =} \code{abline(v =} \code{mean(x),} \code{xpd = FALSE)} for a vertical
203
#'   line at the mean of x).
204
#'
205
#' @return A list containing data and settings is invisibly returned, which might be useful to check for errors.
206
#' Each of these objects can also be pulled from within \code{add}:
207
#' \tabular{ll}{
208
#'   \code{dat} \tab a \code{data.frame} of processed, unsegmented data.\cr
209
#'   \code{cdat} \tab a \code{list} of \code{list}s of \code{data.frame}s of processed, segmented data.\cr
210
#'   \code{txt} \tab a \code{list} of variable names. used mostly to pull variables from \code{data} or the environment.\cr
211
#'   \code{ptxt} \tab a \code{list} of processed variable and level names. Used mostly for labeling.\cr
212
#'   \code{seg} \tab a \code{list} containing segmentation information (such as levels) for each variable.\cr
213
#'   \code{ck} \tab a \code{list} of settings.\cr
214
#'   \code{lega} \tab a \code{list} of arguments that were or would have been passed to \code{\link[graphics]{legend}}.\cr
215
#'   \code{fmod} \tab an \code{lm} object if \code{model} is \code{TRUE}, and the model succeeded.
216
#' }
217
#'
218
#' @section Input:
219
#' \strong{formulas}
220
#'
221
#' When \code{y} is a formula (has a \code{~}), other variables will be pulled from it:
222
#'
223
#' \code{y ~ x * by * between[1] * between[2] + cov[1] + cov[2] + cov[n]}
224
#'
225
#' If \code{y} has multiple variables, \code{by} is used to identify the variable (it becomes a factor with variable names
226
#' as levels), so anything entered as \code{by} is treated as \code{between[1]}, \code{between[1]} is moved to
227
#' \code{between[2]}, and \code{between[2]} is discarded with a message.
228
#'
229
#' \strong{named vectors}
230
#'
231
#' Named vector arguments like \code{font}, \code{cex}, and \code{drop} can be set with a single value, positionally, or
232
#' with names. If a single value is entered (e.g., \code{drop = FALSE}), this will be applied to each level (i.e.,
233
#' \code{c(x = FALSE, by = FALSE, bet = FALSE)}). If more than one value is entered, these will be treated positionally
234
#' (e.g., \code{cex =} \code{c(2, 1.2)} would be read as \code{c(title = 2, sud = 1.2, leg = .9, note = .7, points = 1)}).
235
#' If values are named, only named values will be set, with other defaults retained (e.g., \code{cex =} \code{c(note = 1.2)}
236
#' would be read as \code{c(title = 1.5, sud = .9, leg = .9, note = 1.2, points = 1)}).
237
#'
238
#' @note
239
#' \strong{x-axis levels text}
240
#'
241
#' If the text of x-axis levels (those corresponding to the levels of \code{x}) are too long, they are hidden before
242
#' overlapping. To try and avoid this, by default longer texts are trimmed (dictated by \code{labels.trim}), and at some
243
#' point the orientation of level text is changed (settable with \code{xlas}), but you may still see level text missing.
244
#' To make these visible, you can reduce \code{labels.trim} from the default of 20 (or rename the levels of that variable),
245
#' make the level text vertical (\code{xlas = 3}), or expand your plot window if possible.
246
#'
247
#' \strong{missing levels, lines, and/or error bars}
248
#'
249
#' By default (if \code{drop = TRUE}), levels of \code{x} with no data are dropped, so you may not see every level of your
250
#' variable, at all or at a level of \code{by} or \code{between}. Sometimes error bars cannot be estimated (if, say, there
251
#' is only one observation at the given level), but lines are still drawn in these cases, so you may sometimes see levels
252
#' without error bars even when error bars are turned on. Sometimes (particularly when \code{drop['x']} is \code{FALSE}),
253
#' you might see floating error bars with no lines drawn to them, or what appear to be completely empty levels. This
254
#' happens when there is a missing level of \code{x} between two non-missing levels, potentially making an orphaned level
255
#' (if a non-missing level is surrounded by missing levels). If there are no error bars for this orphaned level, by default
256
#' nothing will be drawn to indicate it. If you set \code{line.type} to \code{'b'} (or any other type with points), a point
257
#' will be drawn at such error-bar-less, orphaned levels.
258
#'
259
#' \strong{unexpected failures}
260
#'
261
#' splot tries to clean up after itself in the case of an error, but you may still run into errors that break things before
262
#' this can happen. If after a failed plot you find that you're unable to make any new plots, or new plots are drawn over
263
#' old ones, you might try entering \code{dev.off()} into the console. If new plots look off (splot's
264
#' \code{\link[graphics]{par}} settings didn't get reset), you may have to close the plot window to reset
265
#' \code{\link[graphics]{par}} (if you're using RStudio, Plots > "Remove Plot..." or "Clear All..."), or restart R.
266
#'
267
#' @examples
268
#' # simulating data
269
#' n <- 2000
270
#' dat <- data.frame(sapply(c("by", "bet1", "bet2"), function(c) sample(0:1, n, TRUE)))
271
#' dat$x <- with(
272
#'   dat,
273
#'   rnorm(n) + by * -.4 + by * bet1 * -.3 + by * bet2 *
274
#'     .3 + bet1 * bet2 * .9 - .8 + rnorm(n, 0, by)
275
#' )
276
#' dat$y <- with(
277
#'   dat,
278
#'   x * .2 + by * .3 + bet2 * -.6 + bet1 * bet2 * .8 + x *
279
#'     by * bet1 * -.5 + x * by * bet1 * bet2 * -.5
280
#'     + rnorm(n, 5) + rnorm(n, -1, .1 * x^2)
281
#' )
282
#'
283
#' # looking at the distribution of y between bets split by by
284
#' splot(y, by = by, between = c(bet1, bet2), data = dat)
285
#'
286
#' # looking at quantile splits of y in y by x
287
#' splot(y ~ x * y, dat, split = "quantile")
288
#'
289
#' # looking at y by x between bets
290
#' splot(y ~ x, dat, between = c(bet1, bet2))
291
#'
292
#' # sequentially adding levels of split
293
#' splot(y ~ x * by, dat)
294
#' splot(y ~ x * by * bet1, dat)
295
#' splot(y ~ x * by * bet1 * bet2, dat)
296
#'
297
#' # same as the last but entered by name
298
#' splot(y, x = x, by = by, between = c(bet1, bet2), data = dat)
299
#'
300
#' # zooming in on one of the windows
301
#' splot(y ~ x * by, dat, bet1 == 1 & bet2 == 0)
302
#'
303
#' # comparing an adjusted lm prediction line with a loess line
304
#' # this could also be entered as y ~ poly(x,3)
305
#' splot(y ~ x + x^2 + x^3, dat, bet1 == 1 & bet2 == 0 & by == 1, add = {
306
#'   lines(x[order(x)], loess(y ~ x)$fitted[order(x)], lty = 2)
307
#'   legend("topright", c("lm", "loess"), lty = c(1, 2), lwd = c(2, 1), bty = "n")
308
#' })
309
#'
310
#' # looking at different versions of x added to y
311
#' splot(cbind(
312
#'   Raw = y + x,
313
#'   Sine = y + sin(x),
314
#'   Cosine = y + cos(x),
315
#'   Tangent = y + tan(x)
316
#' ) ~ x, dat, myl = c(-10, 15), lines = "loess", laby = "y + versions of x")
317
#'
318
#' @export
319
#' @importFrom grDevices grey dev.copy dev.size dev.off cairo_pdf adjustcolor colors col2rgb
320
#' @importFrom graphics axis axTicks hist legend lines text mtext plot barplot par points arrows strwidth layout plot.new
321
#' locator strheight polygon abline
322
#' @importFrom stats density median quantile sd lm glm confint update loess smooth.spline formula as.formula predict
323
#' var binomial
324
325
splot <- function(
326
    y, data = NULL, su = NULL, type = "", split = "median", levels = list(), sort = NULL,
327
    error = "standard", error.color = "#585858", error.lwd = 2, lim = 9, lines = TRUE, ...,
328
    colors = "pastel", colorby = NULL, colorby.leg = TRUE, color.lock = FALSE, color.offset = 1.1,
329
    color.summary = "mean", opacity = 1, dark = getOption("splot.dark", FALSE), x = NULL,
330
    by = NULL, between = NULL, cov = NULL, line.type = "l", mv.scale = "none", mv.as.x = FALSE,
331
    save = FALSE, format = cairo_pdf, dims = dev.size(), file.name = "splot", myl = NULL,
332
    mxl = NULL, autori = TRUE, xlas = 0, ylas = 1, xaxis = TRUE, yaxis = TRUE, breaks = "sturges",
333
    density.fill = TRUE, density.opacity = .4, density.args = list(), leg = "outside",
334
    lpos = "auto", lvn = TRUE, leg.title = TRUE, leg.args = list(), title = TRUE, labx = TRUE,
335
    laby = TRUE, lty = TRUE, lwd = 2, sub = TRUE, ndisp = TRUE, note = TRUE,
336
    font = c(title = 2, sud = 1, leg = 1, leg.title = 2, note = 3),
337
    cex = c(title = 1.5, sud = .9, leg = .9, note = .7, points = 1), sud = TRUE, labels = TRUE,
338
    labels.filter = "_", labels.trim = 20, points = TRUE, points.first = TRUE, byx = TRUE,
339
    drop = c(x = TRUE, by = TRUE, bet = TRUE), prat = c(1, 1), check.height = TRUE, model = FALSE,
340
    options = NULL, add = NULL) {
341
  # parsing input and preparing data
34233x
  if (check.height && dev.size()[2] < 1.7) {
343!
    stop("the plot window seems too short; increase the height of the plot window, or set check.height to FALSE",
344!
      call. = FALSE
345
    )
346
  }
34733x
  if (!missing(options) && is.list(options) && length(options) != 0) {
348!
    a <- as.list(match.call())[-1]
349!
    options <- tryCatch(options, error = function(e) NULL)
350!
    if (is.null(options)) stop("could not find options")
351!
    return(do.call(splot, c(a[names(a) != "options"], options[!names(options) %in% names(a)]), envir = parent.frame()))
352
  }
353!
  if (!labels) title <- sud <- sub <- labx <- laby <- note <- FALSE
35433x
  opt_saf <- getOption("stringsAsFactors")
35533x
  on.exit(options(stringsAsFactors = opt_saf))
35633x
  options(stringsAsFactors = FALSE)
35733x
  ck <- list(
35833x
    ff = list(bet = FALSE, cov = FALSE),
35933x
    t = if (grepl("^b|^l", type, TRUE)) 1 else if (grepl("^d", type, TRUE)) 2 else 3,
36033x
    b = grepl("^b", type, TRUE),
36133x
    tt = !missing(type) && !grepl("^b|^l", type, TRUE),
36233x
    d = !missing(data) && !is.null(data),
36333x
    su = !missing(su),
36433x
    c = !missing(cov),
36533x
    co = missing(colors),
36633x
    cb = !missing(colorby),
36733x
    cblegm = missing(colorby.leg),
36833x
    cbleg = is.logical(colorby.leg) && colorby.leg,
36933x
    poly = missing(density.fill) || (!is.logical(density.fill) || density.fill),
37033x
    polyo = !missing(density.fill) || !missing(density.opacity),
37133x
    e = grepl("^s", error, TRUE),
37233x
    el = !(is.logical(error) && !error),
37333x
    sp = if (!is.character(split)) {
374!
      4
37533x
    } else if (grepl("^mea|^av", split, TRUE)) {
3762x
      1
37733x
    } else if (grepl("^q", split, TRUE)) {
378!
      2
379
    } else {
38031x
      ifelse(grepl("^s", split, TRUE), 3, 4)
381
    },
38233x
    ly = !(is.logical(laby) && !laby) || is.character(laby),
38333x
    lys = is.character(laby),
38433x
    lx = !(is.logical(labx) && !labx) || is.character(labx),
38533x
    line = substitute(lines),
38633x
    lty = is.logical(lty),
38733x
    ltym = missing(lty),
38833x
    ltm = missing(line.type),
38933x
    leg = if (is.logical(leg) && !leg) 0 else if (!is.character(leg) || grepl("^o", leg, TRUE)) 1 else 2,
39033x
    legm = missing(leg),
39133x
    legt = !(is.logical(leg.title) && !leg.title),
39233x
    lp = is.character(lpos) && grepl("^a", lpos, TRUE),
39333x
    lpm = is.character(lpos) && grepl("^p|^m", lpos, TRUE),
39433x
    mod = !missing(x) && model,
39533x
    note = !is.character(note),
39633x
    mv = FALSE,
39733x
    mlvn = missing(lvn),
39833x
    opacity = !missing(opacity) && opacity <= 1 && opacity > 0,
39933x
    mai = FALSE
400
  )
401!
  if (ck$lpm) lpos <- "center"
40233x
  if (ck$d && !is.data.frame(data)) {
403!
    data <- if (!is.matrix(data) && !is.list(data)) {
404!
      as.data.frame(as.matrix(data))
405
    } else {
406!
      as.data.frame(data)
407
    }
408
  }
40933x
  ck$ltck <- (is.logical(ck$line) && ck$line) || !grepl("^F", ck$line)
410!
  if (!ck$ltck && ck$note) note <- FALSE
41133x
  ck$ltco <- if (ck$ltck) if (is.logical(ck$line) || ck$c || grepl("^li|^lm|^st", ck$line, TRUE)) "li" else if (grepl("^loe|^po|^cu", ck$line, TRUE)) "lo" else if (grepl("^sm|^sp|^in", ck$line, TRUE)) "sm" else if (grepl("^e|^co|^d", ck$line, TRUE)) "e" else if (grepl("^pr|^log", ck$line, TRUE)) "pr" else "li" else "li"
41233x
  if (any(!missing(font), !missing(cex), !missing(drop))) {
413!
    dop <- formals(splot)[c("font", "cex", "drop")]
414!
    oco <- function(s, d) {
415!
      od <- d <- eval(d)
416!
      if (length(s) != length(d)) {
417!
        n <- NULL
418!
        if (!is.null(n <- names(s)) || length(s) != 1) if (!is.null(n)) d[n] <- s[n] else d[seq_along(s)] <- s else d[] <- s
419!
        s <- d
420
      }
421!
      s <- s[names(od)]
422!
      names(s) <- names(od)
423!
      if (any(n <- is.na(s))) s[n] <- od[n]
424!
      s
425
    }
426!
    if (!missing(font)) font <- oco(font, dop$font)
427!
    if (!missing(cex)) cex <- oco(cex, dop$cex)
428!
    if (!missing(drop)) drop <- oco(drop, dop$drop)
429
  }
43033x
  dn <- if (ck$d) names(data) else ""
43133x
  if (any(grepl("~", c(substitute(y), if (paste(deparse(substitute(y)), collapse = "") %in% ls(envir = globalenv())) y), fixed = TRUE))) {
43224x
    f <- as.character(as.formula(y))[-1]
43324x
    y <- as.formula(y)[[2]]
43424x
    bl <- function(x) {
43524x
      cs <- strsplit(x, "")[[1]]
43624x
      rs <- lapply(c("(", ")", "[", "]"), grep, cs, fixed = TRUE)
43724x
      l <- vapply(rs, length, 0)
43824x
      cr <- TRUE
43924x
      if (any(l != 0)) {
440!
        if (l[1] != l[2] || l[3] != l[4]) stop("invalid parentheses or brackets in ", x)
441!
        cr <- !seq_along(cs) %in% c(
442!
          unlist(lapply(seq_len(l[1]), function(r) do.call(seq, lapply(rs[1:2], "[[", r)))),
443!
          unlist(lapply(seq_len(l[3]), function(r) do.call(seq, lapply(rs[3:4], "[[", r))))
444
        )
445
      }
44624x
      cs[cr] <- sub("*", "_VAR_", sub("+", "_COV_", cs[cr], fixed = TRUE), fixed = TRUE)
44724x
      paste(cs, collapse = "")
448
    }
44924x
    f <- strsplit(bl(f[-1]), " _COV_ ", fixed = TRUE)[[1]]
45024x
    if (any(grepl(" _VAR_ ", f, fixed = TRUE))) {
4517x
      r <- strsplit(f[1], " _VAR_ ", fixed = TRUE)[[1]]
4527x
      if (length(r)) x <- r[1]
4537x
      if (length(r) > 1) by <- r[2]
4547x
      if (length(r) > 2) {
4554x
        ck$ff$bet <- TRUE
4564x
        between <- r[3]
457
      }
4582x
      if (length(r) > 3) between <- c(r[3], r[4])
4597x
      f <- f[!grepl(" _VAR_ ", f, fixed = TRUE)]
460
    } else {
46117x
      x <- f[1]
46217x
      f <- f[-1]
463
    }
46424x
    if (length(f)) {
465!
      cov <- f
466!
      ck$c <- ck$ff$cov <- TRUE
467
    }
468
  }
46933x
  txt <- list(
47033x
    split = "none",
47133x
    y = substitute(y),
47233x
    x = substitute(x),
47333x
    by = substitute(by),
47433x
    bet = as.list(substitute(between)),
47533x
    cov = as.list(substitute(cov)),
47633x
    su = deparse(substitute(su))
477
  )
47833x
  txt[c("bet", "cov")] <- lapply(c("bet", "cov"), function(l) {
47966x
    paste(if (!ck$ff[[l]] && length(txt[[l]]) > 1) txt[[l]][-1] else txt[[l]])
480
  })
48133x
  txt <- lapply(txt, function(e) if (is.call(e)) paste(deparse(e), collapse = "\n") else e)
482!
  if (length(txt$bet) > 2) txt$bet <- txt$bet[1:2]
48333x
  tdc <- function(x, l = NULL) {
48490x
    if (!is.call(x)) {
48589x
      if ((is.null(l) && length(x) != 1) || (!is.null(l) && length(x) == l)) {
486!
        return(x)
487
      }
488
    }
48960x
    if (is.character(x)) x <- parse(text = x)
49090x
    tx <- tryCatch(eval(x, data, parent.frame(2)), error = function(e) NULL)
49190x
    if (is.character(tx) && length(tx) < 2) {
492!
      x <- parse(text = tx)
493!
      tx <- tryCatch(eval(x, data, parent.frame(2)), error = function(e) NULL)
494!
    } else if (is.null(tx)) tx <- tryCatch(eval(x, data, parent.frame(3)), error = function(e) NULL)
495!
    if (is.null(tx) || any(class(tx) %in% c("name", "call", "expression", "function"))) stop("could not find ", x, call. = FALSE)
49690x
    if (!is.null(l) && is.null(ncol(tx))) {
49756x
      if (length(tx) != l) {
498!
        tx <- rep_len(tx, l)
499!
        if (is.call(x)) x <- deparse(x)
500!
        warning(x, " is not the same length as y", call. = FALSE)
501
      }
502
    }
503!
    if (!is.null(dim(tx)) && !is.matrix(tx) && !is.data.frame(tx)) tx <- as.matrix(tx)
50490x
    tx
505
  }
50633x
  if (!missing(data) && !any(class(data) %in% c("matrix", "data.frame"))) {
507!
    data <- if (is.character(data)) eval(parse(text = data)) else eval(data, globalenv())
508
  }
50933x
  dat <- data.frame(y = tdc(txt$y), check.names = FALSE)
51032x
  if (ncol(dat) == 1) names(dat) <- "y"
51133x
  nr <- nrow(dat)
51233x
  lvs <- function(x, s = FALSE) if (is.factor(x)) base::levels(x) else if (s) sort(unique(x[!is.na(x)])) else unique(x[!is.na(x)])
51333x
  for (n in names(txt)[-c(1, 2, 7)]) {
514132x
    l <- length(txt[[n]])
51581x
    if (l == 0) next
51651x
    if (l == nr) {
517!
      dat[, n] <- txt[[n]]
518!
      txt[[n]] <- n
5195x
    } else if (l == 1) dat[, n] <- tdc(txt[[n]], nr) else for (i in seq_along(txt[[n]])) dat[, paste0(n, ".", i)] <- tdc(txt[[n]][[i]], nr)
520
  }
521!
  if (length(txt$y) == nr) txt$y <- "y"
52233x
  if (missing(x) && !is.null(dat$y) && !is.numeric(dat$y)) {
5231x
    dat$x <- dat$y
5241x
    sl <- grepl("^(y|by|bet[.12]{,2})$", colnames(dat))
5251x
    dat$y <- if (sum(sl) == 1) dat[, sl] else do.call(paste, dat[, sl])
5261x
    dat$y <- table(dat$y)[dat$y]
527!
    if (sum(sl) != 1) dat <- dat[, c("y", "x", colnames(dat)[!colnames(dat) %in% c("y", "x")])]
5281x
    if (ck$t != 2) txt[c("y", "x")] <- c("count", txt$y)
5291x
    ck$el <- FALSE
5301x
    if (missing(type)) {
5311x
      ck$b <- TRUE
5321x
      ck$t <- 1
5331x
      ck[c("b", "t", "tt")] <- list(TRUE, 1, FALSE)
534
    }
5351x
    if (missing(autori)) autori <- FALSE
536
  }
53733x
  if (NCOL(dat$x) > 1) {
538!
    ck$c <- TRUE
539!
    txt$cov <- c(txt$x, txt$cov)
540!
    dat$cov <- cbind(dat$cov, dat$x[, -1])
541!
    dat$x <- dat$x[, 1]
542
  }
54333x
  ck$orn <- nr
54433x
  su <- substitute(su)
54533x
  if (ck$su && length(su) != nr) {
546!
    tsu <- tryCatch(eval(su, if (ck$d) data), error = function(e) NULL)
547!
    if (is.null(tsu) || length(tsu) != nr) {
548!
      odat <- dat
549!
      colnames(odat) <- sub("^y\\.", "", colnames(dat))
550!
      tsu <- tryCatch(eval(su, odat), error = function(e) NULL)
551
    }
552!
    if (!is.null(tsu)) {
553!
      tsu[is.na(tsu)] <- FALSE
554!
      su <- tsu
555
    }
556!
    if (is.logical(tsu) && sum(tsu) == 0 || length(tsu) == 0) {
557!
      ck$su <- FALSE
558!
      warning("su excludes all rows, so it was ignored.", .call = FALSE)
559
    }
560
  }
56133x
  tsu <- vapply(dat, is.numeric, TRUE)
56233x
  ck$omitted <- list(
56333x
    na = apply(dat, 1, function(r) any(is.na(r))),
56433x
    inf = apply(dat[, tsu, drop = FALSE], 1, function(r) any(is.infinite(r)))
565
  )
566!
  if (ck$su) ck$omitted$su <- !su
56733x
  ck$omitted$all <- !Reduce("|", ck$omitted)
56833x
  if (any(!ck$omitted$all)) {
569!
    if (any(ck$omitted$all)) {
570!
      odat <- dat[ck$omitted$all, , drop = FALSE]
571!
      dat <- odat
572!
      dn <- colnames(dat)
573!
      if ("x" %in% dn && length(unique(dat$x)) == 1) {
574!
        ck$t <- 2
575!
        dat$x <- NULL
576!
        warning("after omitting, x only had 1 level, so it was dropped")
577
      }
578!
      if ("by" %in% dn && length(unique(dat$by)) == 1) {
579!
        txt$by <- dat$by <- NULL
580!
        warning("after omitting, by only had 1 level, so it was dropped")
581
      }
582!
      if (ck$d) data <- data[ck$omitted$all, , drop = FALSE]
583
    } else {
584!
      stop("this combination of variables/splits has no complete cases")
585
    }
586
  }
58733x
  dn <- colnames(dat)
58833x
  nr <- nrow(dat)
58933x
  if (sum(grepl("^y", dn)) > 1) {
590
    # setting up multiple y variables
5911x
    dn <- grep("^y\\.", dn)
5921x
    ck$mvn <- colnames(dat)[dn]
5931x
    ck$mvnl <- length(ck$mvn)
5941x
    if (any(tcn <- grepl("(V\\d+$|c\\(|y\\.(\\d+$|.*\\.))", ck$mvn))) {
5951x
      ncn <- substitute(y)
5961x
      if (length(ncn) > 1 && length(ncn <- as.character(ncn[-1])) == length(dn)) {
597!
        ck$mvn[tcn] <- paste0("y.", ncn[tcn])
598
      }
599
    }
6001x
    ck$mv <- TRUE
6011x
    if (ck$mlvn) lvn <- FALSE
6021x
    if (!missing(by)) {
603!
      txt$bet <- c(txt$by, txt$bet)
604!
      if (length(txt$bet) > 2) {
605!
        warning("multiple y variables moves by to between, so the second level of between was dropped")
606!
        txt$bet <- txt$bet[1:2]
607!
        dat <- dat[-grep("bet", colnames(dat))[2]]
608
      }
609!
      if (length(txt$bet) > 1) {
610!
        dat$bet.1 <- if (is.factor(dat$by)) dat$by else as.character(dat$by)
611!
        dat$bet.2 <- if (is.factor(dat$bet)) dat$bet else as.character(dat$bet)
612!
        dat$bet <- NULL
613
      } else {
614!
        dat$bet <- if (is.factor(dat$by)) dat$by else as.character(dat$by)
615
      }
616
    }
6171x
    td <- dat
618!
    if (any(ckn <- duplicated(ck$mvn))) ck$mvn[ckn] <- paste0(ck$mvn[ckn], "_", seq_len(sum(ckn)))
6191x
    by <- sub("^y\\.", "", ck$mvn)
620!
    if (any(by == "")) by[by == ""] <- seq_len(sum(by == ""))
6211x
    by <- factor(rep(by, each = nr), levels = by)
6221x
    cncls <- vapply(dat[, dn], function(v) is.numeric(v) || is.integer(v) || is.factor(v), TRUE)
6231x
    if (any(cncls) && any(!cncls)) {
624!
      for (cnc in which(!cncls)) {
625!
        dat[, cnc] <- as.numeric(factor(dat[, cnc], lvs(dat[, cnc])))
626
      }
627
    }
6281x
    dat <- data.frame(y = unlist(dat[, dn], use.names = FALSE))
629!
    if (ncol(td) > length(dn)) dat <- cbind(dat, do.call(rbind, lapply(seq_along(dn), function(i) td[, -dn, drop = FALSE])))
6301x
    if (mv.as.x) {
631!
      txt$by <- txt$x
632!
      txt$x <- if (missing(labx)) "variable" else if (labx == txt$by) paste0(labx, ".1") else labx
633!
      dat$by <- dat$x
634!
      dat$x <- by
635
    } else {
6361x
      txt$by <- "variable"
6371x
      dat$by <- by
638
    }
6391x
    if (missing(leg.title) && !mv.as.x) ck$legt <- FALSE
640!
    if (!missing(levels) && "mv" %in% names(levels)) names(levels)[names(levels) == "mv"] <- txt[[if (mv.as.x) "x" else "by"]]
6411x
    dn <- colnames(dat)
6421x
    if (!missing(mv.scale) && mv.scale != "none") {
643!
      tv <- if (mv.as.x) dat$x else dat$by
644!
      for (g in levels(as.factor(tv))) {
645!
        svar <- tv == g
646!
        cvar <- scale(dat[svar, 1], scale = grepl("^t|z|sc", mv.scale, TRUE))
647!
        if (any(is.na(cvar))) cvar <- dat[svar, 1] - mean(dat[svar, 1], na.rm = TRUE)
648!
        dat[svar, 1] <- cvar
649
      }
650
    }
6511x
    nr <- nrow(dat)
652
  } else {
65332x
    ck$mv <- FALSE
654
  }
65533x
  if (!"x" %in% dn) {
6568x
    ck$t <- 2
6571x
    if (!missing(type) && !grepl("^d", type, TRUE)) warning("x must be included to show other types of splots")
658
  }
65913x
  if (!ck$cb && !"by" %in% dn) ck$leg <- 0
66033x
  if (lim > 20 || (is.logical(lim) && !lim)) {
661!
    lim <- Inf
662!
    if (ck$legm && !ck$cb) ck$leg <- 0
663!
    if (missing(error)) ck$el <- FALSE
664
  }
6651x
  if (ck$ltm && !ck$el) line.type <- "b"
66633x
  if (ck$ltym && is.logical(lines) && !lines) {
667!
    ck$lty <- FALSE
668!
    lty <- 1
669
  }
67033x
  if (!is.numeric(dat$y)) {
671!
    txt$yax <- lvs(dat$y)
672!
    if (!is.logical(dat$y) && !is.factor(dat$y)) dat$y <- factor(dat$y, lvs(dat$y))
673!
    dat$y <- as.numeric(dat$y)
674
  }
67533x
  if ("by" %in% dn && is.character(dat$by) && all(!grepl("[^0-9]", dat$by))) {
676!
    dat$by <- gsub(" ", "0", base::format(dat$by, justify = "right"), fixed = TRUE)
677
  }
67833x
  odat <- dat
679
  # splitting and parsing variables
68033x
  splt_type <- function(x, s) {
6815x
    if (s == 1) {
6822x
      "mean"
6833x
    } else if (s == 3) {
684!
      "standard deviation"
6853x
    } else if (s == 2) {
686!
      "quantile"
6873x
    } else if (s == 4 && is.double(split) && (length(split) != 1 || all(c(
6883x
      sum(split >= x, na.rm = TRUE),
6893x
      sum(split <= x, na.rm = TRUE)
6903x
    ) > 1))) {
691!
      paste(split, collapse = ", ")
6923x
    } else if (s == 4 && is.numeric(split) && split > 1) {
693!
      split <- min(length(x), round(split), na.rm = TRUE)
694!
      paste0("segments (", split, ")")
695
    } else {
6963x
      "median"
697
    }
698
  }
69933x
  splt <- function(x, s) {
7005x
    if (s == 1) {
7012x
      factor(x >= mean(x, na.rm = TRUE) * 1, labels = c("Below Average", "Above Average"))
7023x
    } else if (s == 3) {
703!
      m <- mean(x, na.rm = TRUE)
704!
      s <- sd(x, TRUE)
705!
      cut(x, c(-Inf, m - s, m + s, Inf), labels = c("-1 SD", "Mean", "+1 SD"))
7063x
    } else if (s == 2) {
707!
      cut(x, c(-Inf, quantile(x, na.rm = TRUE)[c(2, 4)], Inf),
708!
        labels = c("2nd Quantile", "Median", "4th Quantile")
709
      )
7103x
    } else if (s == 4 && is.double(split) && (length(split) != 1 || all(c(
7113x
      sum(split >= x, na.rm = TRUE),
7123x
      sum(split <= x, na.rm = TRUE)
7133x
    ) > 1))) {
714!
      cut(x, c(-Inf, split, Inf), paste0("<=", c(split, "Inf")), ordered_result = TRUE)
7153x
    } else if (s == 4 && is.numeric(split) && split > 1) {
716!
      n <- length(x)
717!
      split <- min(n, round(split), na.rm = TRUE)
718!
      factor(paste("seg", rep(seq_len(split), each = round(n / split + .49))[order(order(x))]))
719
    } else {
7203x
      factor(x >= median(x, TRUE) * 1, labels = c("Under Median", "Over Median"))
721
    }
722
  }
72333x
  seg <- list(
72433x
    x = list(e = !missing(x), s = FALSE, i = 2),
72533x
    f1 = list(e = FALSE, s = FALSE, l = "", ll = 1),
72633x
    f2 = list(e = FALSE, s = FALSE, l = "", ll = 1),
72733x
    by = list(e = FALSE, s = FALSE, l = "", ll = 1)
728
  )
72933x
  if (seg$x$e && ck$t != 2) {
73022x
    if ((ck$t == 1 || is.character(dat$x) || is.factor(dat$x) ||
73122x
      (missing(type) && length(unique(dat$x)) < lim))) {
73211x
      dat$x <- if (!is.character(dat$x) && !is.factor(dat$x) && length(unique(dat$x)) > lim) {
7334x
        seg$x$s <- TRUE
734!
        if (missing(type)) ck$t <- 1
7354x
        txt$split <- splt_type(dat$x, ck$sp)
7364x
        splt(dat$x, ck$sp)
737
      } else {
7386x
        if (missing(type)) ck$t <- 1
7397x
        as.factor(dat$x)
740
      }
741
    }
742
  }
74333x
  if (ck$t == 1 || (is.character(dat$x) || is.factor(dat$x))) {
74412x
    seg$x$l <- lvs(dat$x)
745!
    if (length(seg$x$l) == 1) ck$t <- 3
746
  }
74733x
  svar <- NULL
74833x
  cvar <- if (any(grepl("^c", dn))) which(grepl("^c", dn)) else NULL
74933x
  if (any(grepl("^b", dn))) {
75018x
    svar <- which(grepl("^b", dn))
75118x
    for (i in svar) {
75233x
      e <- if (grepl("bet", dn[i])) if (!seg$f1$e) "f1" else "f2" else "by"
75333x
      seg[[e]]$e <- TRUE
75433x
      seg[[e]]$i <- i
75533x
      seg[[e]]$l <- lvs(dat[, i])
75633x
      if (is.factor(dat[, i]) && drop[[dn[i]]]) {
7571x
        seg[[e]]$l <- seg[[e]]$l[seg[[e]]$l %in% dat[, i]]
758
      }
75933x
      seg[[e]]$ll <- length(seg[[e]]$l)
76033x
      if (seg[[e]]$ll > lim && !(is.character(dat[, i]) || is.factor(dat[, i]))) {
7611x
        txt$split <- splt_type(dat[, i], ck$sp)
7621x
        dat[, i] <- splt(dat[, i], ck$sp)
7631x
        seg[[e]]$s <- TRUE
7641x
        seg[[e]]$l <- lvs(dat[, i])
7651x
        seg[[e]]$ll <- length(seg[[e]]$l)
766
      }
76733x
      if (!is.factor(dat[, i])) {
76831x
        dat[, i] <- if (is.character(dat[, i])) {
7691x
          factor(dat[, i], lvs(dat[, i]))
770
        } else {
77130x
          as.factor(dat[, i])
772
        }
773
      }
774
    }
775
  }
77616x
  if (seg$by$l[1] == "") seg$by$l <- "NA"
77733x
  fmod <- NULL
77833x
  vs <- c(y = txt$y, x = txt$x, by = txt$by, bet = txt$bet, cov = txt$cov)
77933x
  colnames(odat) <- vs
78033x
  if (ck$t != 2 && model) {
7812x
    tryCatch(
782
      {
7832x
        mod <- formula(paste(
7842x
          vs["y"], "~", vs["x"],
7852x
          if (seg$by$e) paste0("*", vs["by"]),
7862x
          if (seg$f1$e) paste0("*", vs[grep("^bet", names(vs))[1]]),
7872x
          if (seg$f2$e) paste0("*", vs["bet2"]),
7882x
          if (length(cvar)) paste0("+", paste0(vs["cov"], collapse = "+"))
789
        ))
7902x
        fmod <- lm(mod, odat)
7912x
        if (model) {
7922x
          s <- summary(fmod)
7932x
          s$call <- mod
7942x
          print(s)
795
        }
796
      },
7972x
      error = function(e) warning(paste("summary model failed:", e$message), call. = FALSE)
798
    )
799
  }
80033x
  if (!missing(levels)) {
801!
    tryCatch(
802
      {
803!
        lc <- c("y", "x", "by", "f1", "f2")
804!
        ns <- c(txt$y, txt$x, txt$by, txt$bet, lc)
805!
        lc <- c(lc[seq_len(length(ns) - length(lc))], lc)
806!
        for (n in names(levels)) {
807!
          if (any(cns <- ns %in% n)) {
808!
            sl <- lc[cns <- which(cns)[1]]
809!
            if (sl == "y") {
810!
              sl <- list(i = 1)
811!
              vfac <- txt$yax
812!
              dat$y <- factor(dat$y, labels = vfac)
813
            } else {
814!
              sl <- seg[[sl]]
815!
              vfac <- lvs(dat[, sl$i])
816
            }
817!
            vl <- length(vfac)
818!
            ln <- levels[[n]]
819!
            lo <- NULL
820!
            if (is.list(ln)) {
821!
              if (length(ln) > 1) lo <- levels[[n]][[2]]
822!
              ln <- ln[[1]]
823
            }
824!
            if (is.numeric(ln)) ln <- vfac[ln]
825!
            if (vl == length(ln)) {
826!
              vl <- list(dat[, sl$i])
827!
              if (all(ln %in% vfac)) {
828!
                vl$levels <- ln
829
              } else {
830!
                if (!is.null(lo)) {
831!
                  vl$labels <- ln[lo]
832!
                  vl$levels <- vfac[lo]
833
                } else {
834!
                  vl$labels <- ln
835
                }
836
              }
837!
              dat[, sl$i] <- do.call(factor, vl)
838!
              if ("l" %in% names(sl)) seg[[lc[cns]]]$l <- levels(dat[, sl$i])
839
            } else {
840!
              warning(n, " has ", vl, " levels but you provided ", length(ln), call. = FALSE)
841
            }
842!
            if (sl$i == 1) {
843!
              txt$yax <- lvs(dat$y)
844!
              dat$y <- as.numeric(dat$y)
845
            }
846
          }
847
        }
848
      },
849!
      error = function(e) warning("setting levels failed: ", e$message, call. = FALSE)
850
    )
851
  }
85233x
  dsf <- list(c1 = "", sep = rep.int("^^", nr), c2 = "")
85311x
  if (seg$f1$e) dsf$c1 <- dat[, seg$f1$i]
8545x
  if (seg$f2$e) dsf$c2 <- dat[, seg$f2$i]
85533x
  cdat <- split(dat, dsf)
85633x
  if (seg$by$e) {
85717x
    cdat <- lapply(cdat, function(s) {
85837x
      if (length(unique(s$by)) > 1) {
85937x
        split(s, factor(as.character(s$by), lvs(s$by)))
860
      } else {
861!
        s <- lapply(seg$by$l, function(l) if (sum(s$by == l)) s else NULL)
862!
        names(s) <- seg$by$l
863!
        s
864
      }
865
    })
86617x
    if (all((seg$n <- vapply(cdat, length, 0)) == seg$by$ll)) {
86717x
      seg$n <- vapply(cdat, function(s) vapply(s, NROW, 0), numeric(seg$by$ll))
868
    } else {
869!
      drop["by"] <- FALSE
870
    }
871
  } else {
87216x
    seg$n <- vapply(cdat, nrow, 0)
873
  }
87433x
  if (seg$by$e && ck$t != 3 && drop["by"]) {
87510x
    seg$by$l <- if (is.null(rownames(seg$n))) {
876!
      structure(seg$n > 1, names = seg$by$l)
877
    } else {
87810x
      vapply(rownames(seg$n), function(r) any(seg$n[r, ] > 1), TRUE)
879
    }
88010x
    if (!any(seg$by$l)) {
881!
      if (ck$t == 2) stop("no level of by has more than 1 observation")
882!
      warning("no level of by has more than 1 observation so it was treated as colorby", call. = FALSE)
883!
      seg$by$e <- FALSE
884!
      seg$by$l <- ""
885!
      seg$by$ll <- 1
886!
      if (ck$cb) {
887!
        colorby <- substitute(colorby)
888!
        colorby[[2]] <- dat$by
889
      } else {
890!
        colorby <- dat$by
891
      }
892!
      ck$cb <- TRUE
893!
      dat <- dat[, -seg$by$i]
894!
      cdat <- split(dat, dsf)
895!
      seg$n <- vapply(cdat, nrow, 0)
896
    } else {
89710x
      seg$by$l <- names(seg$by$l[seg$by$l])
89810x
      seg$by$ll <- length(seg$by$l)
899
    }
900
  }
90133x
  if (!is.null(nrow(seg$n))) {
90217x
    cdat <- cdat[apply(seg$n, 2, function(r) any(r > 1))]
90317x
    if (nrow(seg$n) > 1) seg$n <- colSums(seg$n[, names(cdat), drop = FALSE])
904
  }
9051x
  if (ck$mv) seg$n <- seg$n / length(ck$mvn)
90633x
  seg$ll <- length(seg$n)
9072x
  if (ck$mlvn && seg$by$e && (seg$by$s || !any(grepl("^[0-9]", seg$by$l)))) lvn <- FALSE
90833x
  ptxt <- c(txt[-c(1, 7)], l = lapply(seg[1:4], "[[", "l"))
90910x
  if (missing(labels.trim) && seg$ll == 1 && length(ptxt$l.x) < 2 && (seg$by$ll == 1 || ck$mv)) labels.trim <- 40
91033x
  if (is.numeric(labels.trim) || is.character(labels.filter)) {
91132x
    vs <- c("y", "x", "by", "bet", "cov", "l.x", "l.f1", "l.f2", "l.by")
91232x
    ptxt <- lapply(vs, function(n) {
913288x
      n <- as.character(ptxt[[n]])
914288x
      if (length(n) != 0 && all(n != "NULL" & n != "")) {
915144x
        names(n) <- n
916144x
        if (is.character(labels.filter)) n <- gsub(labels.filter, " ", n, perl = TRUE)
917!
        if (any(is.na(iconv(n)))) stop("labels appear to be misencoded -- check them with the iconv function")
918!
        if (is.numeric(labels.trim)) if (any(ln <- nchar(n) > (labels.trim + 3))) n[ln] <- sub("$", "...", strtrim(n[ln], labels.trim))
919
      }
920288x
      n
921
    })
92232x
    names(ptxt) <- vs
923
  }
924!
  if (is.character(labx)) ptxt$x <- labx else if (ck$t == 2) ptxt$x <- ptxt$y
925!
  if (is.character(laby)) ptxt$y <- laby else if (ck$t == 2) ptxt$y <- "Density"
92633x
  ck$ileg <- seg$by$e && ck$leg > 1
92733x
  ptxt$leg <- ptxt$l.by
92833x
  fdat <- dat
92933x
  names(fdat) <- paste0(".", names(dat))
93033x
  fdat <- if (!is.null(data)) if (nrow(data) == nr) cbind(data, fdat, odat) else data else cbind(fdat, odat)
931
  # figuring out colors
93233x
  csf <- if (is.function(color.summary)) {
933!
    color.summary
93433x
  } else if (grepl("^av|mea", color.summary, TRUE)) {
93533x
    splot.colormean
93633x
  } else if (grepl("^mode", color.summary, TRUE)) {
937!
    function(x) names(which.max(table(x)))
938
  } else {
939!
    function(x) lvs(x)[round(median(as.numeric(factor(x, lvs(x)))))]
940
  }
94133x
  colors <- substitute(colors)
94233x
  seg$cols <- if (ck$co) colors else if (any(paste(colors) %in% names(fdat))) NULL else tryCatch(tdc(colors), error = function(e) NULL)
9431x
  if (is.null(seg$cols)) seg$cols <- eval(colors, fdat, parent.frame(1))
94433x
  ptxt$cbo <- substitute(colorby)
945!
  if (length(ptxt$cbo) > 1 && ptxt$cbo[[1]] == "list") ptxt$cbo <- ptxt$cbo[[2]]
94633x
  if (!is.character(ptxt$cbo)) ptxt$cbo <- deparse(ptxt$cbo)
94733x
  if (length(seg$cols) == 1) {
94832x
    if (grepl("^bri|^dar|^pas", seg$cols, TRUE) && (ck$cb || (seg$by$ll > 1 && seg$by$ll < 10))) {
94920x
      seg$cols <- splot.color(seed = seg$cols)
95012x
    } else if (ck$co || grepl("^gra|^grey", seg$cols, TRUE)) seg$cols <- splot.color(seg$by$ll, seed = "grey")
951
  }
95233x
  cl <- length(seg$cols)
95333x
  seg$lcols <- seg$cols
95433x
  ck[c("cbn", "cbb")] <- tg <- FALSE
95533x
  chl <- if (ck$cblegm) FALSE else ck$cbleg
95633x
  if (ck$cb) {
9573x
    sca <- names(formals(splot.color))
9583x
    colorby <- substitute(colorby)
9593x
    cba <- if (any(paste(colorby) %in% names(fdat))) NULL else tryCatch(tdc(colorby), error = function(e) NULL)
9602x
    if (is.null(cba)) cba <- eval(substitute(colorby), fdat)
961!
    if (is.null(cba) || (is.character(cba) && length(cba) == 1)) cba <- tdc(colorby)
9623x
    if (!is.list(cba) || is.data.frame(cba)) {
9633x
      cba <- list(x = cba)
964!
    } else if (is.null(names(cba))) {
965!
      names(cba) <- names(formals(splot.color))[seq_along(cba)]
966!
    } else if (any(names(cba) == "")) {
967!
      tn <- names(cba) == ""
968!
      names(cba)[tn] <- sca[seq_len(sum(tn))]
969
    }
9703x
    if (!is.null(ncol(cba$x)) && ncol(cba$x) > 1) {
971!
      if (!"by" %in% names(cba)) cba$by <- cba$x[, 2]
972!
      cba$x <- cba$x[, 1]
973
    }
9743x
    cba$flat <- TRUE
9753x
    cn <- names(cba)
9763x
    ck$cbb <- "by" %in% cn
9773x
    if (ck$mv && length(cba$x) * ck$mvnl == nr) {
978!
      cba$x <- rep(cba$x, ck$mvnl)
979!
      if (ck$cbb) cba$by <- rep(cba$by, ck$mvnl)
980
    }
9813x
    if (ck$cbb) {
982!
      cba$by <- if (is.numeric(cba$by) && length(unique(cba$by)) > lim) {
983!
        ptxt$cbos <- if (missing(leg.title)) colorby else leg.title
984!
        ptxt$cbos <- if (is.call(ptxt$cbos)) {
985!
          deparse(ptxt$cbos[[if (cn[2] == "by" && length(ptxt$cbos) > 2) 3 else 2]])
986
        } else {
987!
          deparse(ptxt$cbos)
988
        }
989!
        splt(cba$by, ck$sp)
990
      } else {
991!
        factor(cba$by, lvs(cba$by))
992
      }
993!
      if (seg$by$e && seg$by$ll <= lim && length(cba$by) == nr && !identical(as.character(dat$by), as.character(cba$by))) {
994!
        cba$by <- dat$by:cba$by
995!
        cbbl <- sub(":.*", "", lvs(cba$by))
996!
        colorby[[3]] <- as.name(paste0(ptxt$by, ":", colorby[[3]]))
997!
        seg$lcols <- seg$cols <- splot.color(cbbl, seed = seg$cols)
998!
        if (!ck$b && ck$line) {
999!
          if (length(lty) < seg$by$ll) lty <- seq_len(seg$by$ll)
1000!
          ck[c("lty", "ltym")] <- FALSE
1001!
          lty <- rep(lty, table(cbbl))
1002!
          seg$lty <- unique(lty)
1003
        }
1004
      } else {
1005!
        lby <- length(lvs(cba$by))
1006!
        if (!color.lock && cl < lby) seg$cols <- splot.color(as.list(rep.int(round(lby / cl + .49), cl)), seed = seg$cols)
1007
      }
1008
    }
10093x
    if (length(cba$x) == ck$orn) cba$x <- cba$x[ck$omitted$all]
1010!
    if (ck$cbb && length(cba$by) == ck$orn) cba$by <- cba$by[ck$omitted$all]
10113x
    if (seg$by$e || !"seed" %in% cn) {
10123x
      cba$seed <- seg$cols
10133x
      if ("seed" %in% cn) {
1014!
        warning("colorby's seed is ignored because by is specified -- use colors to set seeds", call. = FALSE)
1015
      }
1016
    }
10173x
    cn <- names(cba)
10183x
    ckn <- cken <- is.numeric(cba$x)
10193x
    if ((ck$t == 1 || any(seg$by$e, seg$f1$e)) && length(cba$x) == nr) {
10201x
      seg$cbxls <- lvs(cba$x)
10211x
      if (ck$t != 3 && (!seg$by$e || seg$by$ll > lim)) {
10221x
        cba$x <- vapply(split(cba$x, if (seg$by$e) dat$by else dat$x), function(x) {
10232x
          if (ckn) {
10242x
            mean(x, na.rm = TRUE)
1025
          } else {
1026!
            names(which.max(table(x)))
1027
          }
10281x
        }, if (ckn) 0 else "")
10291x
        if (!ckn || length(seg$cbxls) <= lim) {
1030!
          cba$x <- if (ckn) {
1031!
            cba$x <- round(cba$x, 3)
1032!
            factor(cba$x, sort(unique(cba$x)))
1033
          } else {
1034!
            factor(cba$x, seg$cbxls)
1035
          }
1036!
          ckn <- FALSE
1037
        }
10381x
        if (ck$cbb && length(cba$by) == nr) {
1039!
          cba$by <- factor(vapply(split(cba$by, if (seg$by$e) dat$by else dat$x), function(x) {
1040!
            names(which.max(table(x)))
1041!
          }, ""), lvs(cba$by))
1042!
          if (length(cba$x) != length(cba$by)) {
1043!
            cba$by <- NULL
1044!
            ck$cbb <- FALSE
1045!
            warning("colorby's by was dropped as it was not the same length as x after being aligned with the formula's x",
1046!
              call. = FALSE
1047
            )
1048
          }
1049
        }
10501x
        if (ckn && !ck$b && ck$t == 1 && length(cba$x) == 2) {
1051!
          cba$x <- c(mean(cba$x), cba$x)
1052!
          if (ck$cbb) cba$by <- factor(c(lvs(cba$by)[which.max(tabulate(cba$by))], as.character(cba$by)), lvs(cba$by))
1053
        }
1054!
      } else if (!ck$cbb) {
1055!
        if (ck$t == 3) {
1056!
          cba$by <- dat$by
1057
        } else {
1058!
          cba$x <- data.frame(cba$x, dat$by)
1059!
          if (ck$b && seg$ll != 1) cba$x$x <- dat$x
1060!
          cba$x <- unlist(lapply(split(cba$x, dsf), function(x) {
1061!
            lapply(
1062!
              split(x[, 1], x[, -1]), function(x) if (!length(x)) NA else if (ckn) mean(x, na.rm = TRUE) else names(which.max(table(x)))
1063
            )
1064!
          }), TRUE, FALSE)
1065!
          if (length(cba$x) == seg$by$ll) names(cba$x) <- seg$by$l else seg$ill <- names(cba$x)
1066!
          if (!ckn) cba$x <- factor(cba$x, seg$cbxls)
1067!
          cba$by <- factor(rep_len(seg$by$l, length(cba$x)), seg$by$l)
1068!
          if (ck$cblegm) ck$cbleg <- FALSE
1069
        }
1070
      }
1071
    }
10723x
    if (ck$cbb) {
1073!
      if (length(cba$by) == nr && length(cba$x) == seg$by$ll) {
1074!
        tn <- lapply(split(cba$by, dat$by), unique)
1075!
        if (all(vapply(tn, length, 0) == 1)) {
1076!
          cba$by <- unlist(tn, use.names = FALSE)
1077
        } else {
1078!
          cba$by <- NULL
1079!
          warning("colorby's by was dropped as its levels within levels of by are not unique", call. = FALSE)
1080
        }
1081
      }
1082!
      if (ck$cbleg) {
1083!
        chl <- TRUE
1084!
        if (missing(leg.title)) {
1085!
          leg.title <- substitute(colorby)
1086!
          leg.title <- if (is.call(leg.title) && length(leg.title) > 2) {
1087!
            deparse(leg.title[[if (cn[2] == "by") 3 else 2]])
1088
          } else {
1089!
            deparse(leg.title)
1090
          }
1091
        }
1092!
        ptxt$leg <- lvs(cba$by)
1093
      }
1094
    } else {
10953x
      if (ck$cbleg && (ck$t == 1 || !seg$by$e)) {
10963x
        chl <- TRUE
10973x
        tg <- ckn
10983x
        ll <- all(ck$t != 1 || (length(seg$x$l) > 2 || seg$by$ll > 2))
10993x
        if (ll) {
1100!
          if (is.call(cba$x)) cba$x <- tdc(cba$x)
11012x
          ll <- length(unique(cba$x)) > 2
1102
        }
11033x
        if (missing(leg.title) && length(ptxt$cbo) == 1) leg.title <- ptxt$cbo
11043x
        ptxt$leg <- if (ckn) formatC(c(min(cba$x), if (ll) mean(cba$x), max(cba$x)), 2, format = "f") else lvs(cba$x)
1105!
      } else if (!seg$by$e) ck$leg <- 0
1106
    }
1107!
    if (!ckn && length(cba$x) > lim && !"shuffle" %in% cn) cba$shuffle <- TRUE
11083x
    sca <- cn %in% sca
1109!
    if (any(!sca)) warning(paste0("unused colorby arguments: ", paste(cn[!sca], collapse = ", ")), call. = FALSE)
11103x
    seg$cols <- do.call(splot.color, cba[sca])
11111x
    if (!is.null(names(cba$x))) names(seg$cols) <- names(cba$x)
11123x
    if (!chl || ck$cbb) {
1113!
      ck$cbn <- TRUE
1114!
      ptxt$cbn <- paste0("Colored by ", if (ckn || cken) "value of " else "levels of ", ptxt$cbo, ". ")
1115
    }
11163x
    if (seg$by$e && !ck$cbb) {
1117!
      if (length(seg$cols) == length(ptxt$leg)) {
1118!
        seg$lcols <- seg$cols
1119!
      } else if (ckn && ck$cbb) {
1120!
        seg$lcols <- seg$cols[c(which.min(cba$x), which.max(cba$x))]
1121
      }
1122
    }
11233x
    if (chl) {
1124!
      if (ck$legm && !ck$leg) ck$leg <- 1 + seg$ll > 1
11253x
      if ((ck$ltym || length(lty) == length(seg$cbxls)) && (!seg$by$e || seg$by$ll > length(ptxt$leg))) {
11263x
        ck[c("lty", "ltym")] <- FALSE
11273x
        if (!is.numeric(lty)) lty <- 1
11283x
        seg$lty <- rep_len(lty, seg$by$ll)
11293x
        if (!ck$ltym) lty <- seq_along(seg$cbxls)
11303x
        if (ck$ltym && seg$by$e && !ckn) {
1131!
          cbl <- cba[[if (ck$cbb) "by" else "x"]]
1132!
          for (g in seq_along(seg$cbxls)) seg$lty[cbl == seg$cbxls[[g]]] <- lty[[g]]
1133
        }
11343x
        lty <- unique(seg$lty)
1135
      }
11363x
      if (tg) {
11373x
        l <- length(seg$cols)
11383x
        seg$lcols <- seg$cols[order(cba$x)[c(1, if (ll) round(mean(seq_len(l))), l)]]
1139!
      } else if (seg$by$e && length(seg$cols) == seg$by$ll && length(ptxt$leg) == seg$by$ll) seg$lcols <- seg$cols
1140
    } else {
1141!
      ptxt$leg <- if (length(seg$cols) == seg$by$ll && !is.null(names(seg$cols))) names(seg$cols) else seg$by$l
1142!
      if (length(ptxt$leg) == length(seg$cols)) seg$lcols <- seg$cols else if (all(ptxt$leg %in% names(seg$cols))) seg$lcols <- seg$cols[ptxt$leg] else if (seg$by$e && length(seg$cols) == nr) seg$lcols <- vapply(split(seg$cols, dat$by), csf, "")
1143
    }
1144
  } else {
114530x
    if (!color.lock && cl < seg$by$ll) {
1146!
      seg$cols <-
1147!
        splot.color(as.list(rep.int(round(seg$by$ll / cl + .49), cl)), seed = seg$cols)
1148
    }
114930x
    if (ck$t != 2 && !any(length(seg$cols) == c(nr, seg$by$ll)) && (!ck$b || seg$by$e)) {
115013x
      seg$cols <- rep_len(seg$cols, seg$by$ll)
1151
    }
1152
  }
115333x
  if (seg$by$e && !all(seg$by$l %in% names(seg$cols))) {
115417x
    if (length(seg$cols) == seg$by$ll) {
115513x
      names(seg$cols) <- seg$by$l
115613x
      if (!ck$cbb && !chl) seg$lcols <- seg$cols
11574x
    } else if (length(seg$lcols) == seg$by$ll) {
1158!
      names(seg$lcols) <- seg$by$l
11594x
    } else if (length(ptxt$leg) == seg$by$ll) {
11604x
      if (length(seg$lcols) == nr) {
1161!
        seg$lcols <- split(seg$lcols, dat$by)
1162
      } else {
11634x
        seg$lcols <- rep_len(seg$lcols, seg$by$ll)
11644x
        if (any(grepl(names(cdat)[1], names(seg$lcols), fixed = TRUE))) {
1165!
          for (g in names(cdat)) names(seg$lcols) <- sub(paste0(g, "."), "", names(seg$lcols), fixed = TRUE)
1166!
          if (all(seg$by$l %in% names(seg$lcols))) seg$lcols <- seg$lcols[seg$by$l]
1167
        } else {
11684x
          names(seg$lcols) <- seg$by$l
1169
        }
1170
      }
1171
    }
117217x
    if (ck$b && length(seg$cols) == nr) {
1173!
      seg$cols <- unlist(lapply(
1174!
        split(data.frame(seg$cols, dat$by), dat$x),
1175!
        function(d) vapply(split(d[, 1], d[, 2], drop = TRUE), csf, "")
1176!
      ), use.names = FALSE)
1177
    }
1178
  }
117933x
  if (ck$opacity && (ck$t != 3 || !points)) {
1180!
    if (is.list(seg$cols)) {
1181!
      lapply(seg$cols, adjustcolor, opacity)
1182
    } else {
1183!
      seg$cols[] <- adjustcolor(seg$cols, opacity)
1184
    }
1185
  }
118615x
  if (lvn && length(ptxt$by)) ptxt$l.by[] <- paste0(paste0(ptxt$by, ": "), ptxt$l.by)
118733x
  if (length(seg$cols) == nr) {
11883x
    if (any(seg$by$e && !ck$b, seg$f1$e, seg$f2$e)) {
11891x
      seg$scols <- split(if (seg$by$e && !ck$b) data.frame(seg$cols, dat$by) else seg$cols, dsf)
11901x
      if (!ck$b) {
1191!
        if (seg$by$e) seg$scols <- lapply(seg$scols, function(d) split(d[, 1], d[, 2]))
1192!
        if (ck$t == 1) {
1193!
          seg$scols <- lapply(seg$scols, function(bl) {
1194!
            vapply(bl, function(bll) {
1195!
              if (length(bll)) csf(bll) else ""
1196
            }, "")
1197
          })
1198
        }
1199
      }
1200
    }
120130x
  } else if (seg$ll != 1 && "ill" %in% names(seg)) {
1202!
    seg$scols <- lapply(names(cdat), function(n) seg$cols[grepl(n, names(seg$cols), fixed = TRUE)])
1203!
    names(seg$scols) <- names(cdat)
1204
  }
120533x
  if (ck$t == 2 && seg$by$ll > 1 && !all(seg$by$l %in% names(seg$cols))) {
12064x
    seg$cols <- if (length(seg$lcols) == seg$by$ll) {
12074x
      seg$lcols
12084x
    } else if (length(seg$cols) == 1) {
1209!
      splot.color(seq_len(seg$by$ll), seed = seg$cols)
1210
    } else {
1211!
      rep_len(seg$cols, seg$by$ll)
1212
    }
1213!
    if (is.null(names(seg$cols))) names(seg$cols) <- seg$by$l
1214
  }
1215
  # figuring out parts of the plot
121633x
  ylab <- if (ck$ly) ptxt$y else ""
121733x
  xlab <- if (ck$lx && length(ptxt$x)) ptxt$x else ""
121833x
  main <- if (is.logical(title) && title) {
121931x
    paste0(if (ck$t == 2) {
12209x
      paste("Density of", ptxt$x)
1221
    } else {
122222x
      paste(
122322x
        ptxt$y,
122422x
        "by", ptxt$x
1225
      )
122631x
    }, if (seg$by$e && !ck$mv) paste(" at levels of", ptxt$by), if (length(ptxt$bet) != 0) {
122710x
      paste(
122810x
        " between",
122910x
        paste(ptxt$bet, collapse = " & ")
1230
      )
1231
    })
123233x
  } else if (is.character(title)) title else ""
123333x
  if (!is.character(note)) {
123432x
    if (!is.logical(note) || note) {
123532x
      ck$er <- ck$t == 1 && ck$el
123632x
      ck$spm <- txt$split != "none"
123732x
      if (ck$er && all(vapply(cdat, function(d) {
12384x
        if (!is.data.frame(d)) all(vapply(d, function(dd) !anyDuplicated(dd$x), TRUE)) else !anyDuplicated(d$x)
123932x
      }, TRUE))) {
1240!
        ck[c("el", "er")] <- FALSE
1241
      }
124232x
      if (any(ck$cbn, ck$spm, ck$er, ck$t == 3 && ck$ltck)) {
124321x
        if (ck$spm) {
12445x
          tv <- unique(c(
12455x
            if (seg$x$s) ptxt$x,
12465x
            if (seg$by$s) ptxt$by,
12475x
            if (seg$f1$s) ptxt$bet[1],
12485x
            if (seg$f2$s) ptxt$bet[2],
12495x
            if ("cbos" %in% names(ptxt)) ptxt$cbos
1250
          ))
12515x
          tv <- sub(", (?=[A-z0-9]+$)", if (length(tv) > 2) ", & " else " & ", paste(tv, collapse = ", "), perl = TRUE)
1252
        }
125321x
        note <- paste0(
125421x
          if (ck$spm) paste0(tv, " split by ", txt$split, ". "),
125521x
          if (ck$er) paste("Error bars show", ifelse(ck$e, "standard error. ", "95% confidence intervals. ")),
125621x
          if (ck$cbn) ptxt$cbn,
125721x
          if (ck$t == 3 && ck$ltck) {
125811x
            paste0("Line type: ", switch(ck$ltco,
125911x
              li = "lm",
126011x
              lo = "loess",
126111x
              sm = "spline",
126211x
              e = "connected",
126311x
              pr = "probability"
1264
            ), ".")
1265
          }
1266
        )
1267
      }
1268
    } else {
1269!
      note <- ""
1270
    }
1271
  }
127233x
  ck$sud <- (!is.logical(sud) || sud) && (is.character(sud) || ck$su || ck$c)
127333x
  ck$sub <- (!is.logical(sub) || sub) && (is.character(sub) || seg$ll > 1 || ndisp)
127433x
  pdo <- list(...)
127533x
  l2m <- function(l) {
12761x
    tl <- round(l^.5)
12771x
    c(tl + all(l > c(tl^2, tl * (tl - 1))), tl)
1278
  }
127933x
  seg$dim <- if (any(ckl <- c("mfrow", "mfcol") %in% names(pdo))) {
1280!
    pdo[[if (ckl[1]) "mfrow" else "mfcol"]]
128133x
  } else if (!seg$f1$e) {
128222x
    c(1, 1)
128333x
  } else if (!seg$f2$e) {
12846x
    if (seg$f1$ll > 2) l2m(seg$f1$ll) else c(2, 1)
1285
  } else {
12865x
    c(seg$f1$ll, seg$f2$ll)
1287
  }
128833x
  seg$l <- t(data.frame(strsplit(names(cdat), ".^^.", fixed = TRUE)))
128933x
  if (seg$f1$e) {
129011x
    rownames(seg$l) <- match(seg$l[, 1], seg$f1$l)
129111x
    seg[c("f1", "f2")] <- lapply(c("f1", "f2"), function(n) {
129222x
      nl <- seg[[n]]
129316x
      if (nl$e) nl$l <- unique(seg$l[, if (n == "f1") 1 else 2])
129416x
      if (nl$e) nl$ll <- length(nl$l)
129522x
      nl
1296
    })
1297
  }
129833x
  nc <- seg$dim[1] * seg$dim[2]
129913x
  if (length(ptxt$leg) == 1 && ptxt$leg == "NA") ck$leg <- 0
130033x
  if (ck$leg == 1 && ck$legm && (dev.size(units = "in")[1] < 2 ||
130133x
    (all(seg$dim == 1) && (ck$t != 1 || seg$by$ll < 9)))) {
130210x
    ck$leg <- 2
1303
  }
130410x
  if (ck$leg == 1) if (is.logical(leg) || is.character(leg)) leg <- nc + 1
130533x
  dop <- par(no.readonly = TRUE)
130633x
  if (drop["bet"] && !any(ckl) && any(nc - seg$ll >= seg$dim)) {
13071x
    seg$dim <- l2m(seg$ll)
13081x
    nc <- seg$dim[1] * seg$dim[2]
1309
  }
131033x
  seg$dmat <- matrix(seq_len(nc), seg$dim[2], seg$dim[1])
131133x
  if (!drop["bet"] && seg$f2$e) {
1312!
    seg$lc <- vapply(seg$f1$l, function(l) seg$f2$l %in% seg$l[seg$l[, 1] == l, 2], logical(seg$f2$ll))
1313
  } else {
131433x
    seg$lc <- seg$dmat == 0
131533x
    seg$lc[seq_len(seg$ll)] <- TRUE
1316
  }
131733x
  if (nc > seg$ll) {
1318!
    if (any(ckl)) {
1319!
      tm <- lapply(dim(seg$lc), seq_len)
1320!
      mm <- matrix(FALSE, seg$dim[2], seg$dim[1])
1321!
      mm[tm[[1]], tm[[2]]] <- seg$lc
1322!
      seg$lc <- mm
1323
    }
1324!
    if (!drop["bet"]) {
1325!
      seg$dmat[seg$lc] <- seq_len(seg$ll)
1326!
      seg$dmat[!seg$lc] <- seq_len(sum(!seg$lc)) + seg$ll
1327
    }
1328
  }
132933x
  ck$legcol <- FALSE
133033x
  if (lpos == "auto") "topright"
133133x
  lega <- list(x = lpos, col = seg$lcols, cex = cex["leg"], text.font = font["leg"], bty = "n", x.intersp = .5, xjust = .5, legend = ptxt$leg)
133233x
  if (ck$legt && (is.character(leg.title) && length(leg.title) == 1 || length(ptxt$by) == 1)) {
133319x
    lega$title <- if (is.character(leg.title)) leg.title else ptxt$by
1334
  }
133533x
  l <- length(lega$legend)
133633x
  seg$lwd <- rep_len(if (is.numeric(lwd)) lwd else 2, seg$by$ll)
133730x
  if (!"lty" %in% names(seg)) seg$lty <- rep_len(if (!ck$ltym && !ck$lty) lty else if (ck$cbleg && ck$cbb && seg$by$ll == length(cba$by)) as.numeric(cba$by) else if (ck$lty && lty) seq_len(6) else 1, seg$by$ll)
133831x
  if (length(seg$cols) == length(seg$lcols)) names(seg$lcols) <- names(seg$cols)
133917x
  if (seg$by$e || ck$cbb) names(seg$lwd) <- names(seg$lty) <- if (length(seg$lcols) == seg$by$ll) names(seg$lcols) else if (all(c(length(seg$lwd), length(seg$lty)) == length(seg$cols))) names(seg$cols) else seg$by$l
134033x
  lega$lwd <- if (seg$by$ll == l) seg$lwd else rep_len(if (is.numeric(lwd)) lwd else 2, l)
134133x
  lega$lty <- if (seg$by$ll == l) seg$lty else rep_len(if (!ck$ltym && !ck$lty) lty else if (ck$lty && lty) seq_len(6) else 1, l)
1342!
  if (!missing(leg.args)) lega[names(leg.args)] <- leg.args
134333x
  if (any(tck <- !names(lega) %in% names(formals(legend)))) {
1344!
    warning("dropped items from leg.args: ", paste(names(lega)[tck], collapse = ", "), call. = FALSE)
1345!
    lega <- lega[!tck]
1346
  }
134733x
  if ((ck$legm || !ck$leg) && missing(leg.args) && (sum(strheight(lega$legend, "i")) * cex["leg"] * 1.5 / if ("ncol" %in% names(pdo)) {
1348!
    pdo$ncol
1349
  } else {
135033x
    1
135133x
  }) > dev.size()[2]) {
1352!
    ck$leg <- 0
1353!
    if (ck$ltym) seg$lty[] <- 1
1354
  }
135533x
  if (ck$leg == 1) {
1356!
    if (ck$legm && nc > seg$ll) leg <- which(!seg$lc)[1]
135710x
    if (nc > seg$ll && leg <= nc) {
1358!
      if (seg$lc[leg] && !drop["bet"]) {
1359!
        mm <- which(!seg$lc)
1360!
        leg <- mm[which.min(abs(mm - leg))]
1361
      }
1362!
      if (seg$lc[leg]) {
1363!
        seg$lc[] <- TRUE
1364!
        seg$lc[leg] <- FALSE
1365!
        seg$lc[seg$lc][bsq <- seq_len(nc - seg$ll - 1) + seg$ll] <- FALSE
1366!
        seg$dmat[seg$lc] <- seq_len(seg$ll)
1367!
        seg$dmat[leg] <- seg$ll + 1
1368!
        seg$lc[leg] <- TRUE
1369!
        seg$dmat[!seg$lc] <- bsq + 1
1370
      } else {
1371!
        seg$lc[leg] <- TRUE
1372!
        seg$dmat[leg] <- seg$ll + 1
1373!
        seg$dmat[!seg$lc] <- seq_len(sum(!seg$lc)) + seg$ll + 1
1374
      }
1375!
      if (ck$lp) lega$x <- "center"
137610x
    } else if (ck$lp) lega$x <- "right"
137710x
    if (nc == seg$ll || leg > nc) {
137810x
      seg$dmat[seg$dmat == seg$ll + 1] <- nc + 1
137910x
      seg$dmat <- rbind(seg$dmat, rep.int(seg$ll + 1, seg$dim[1]))
138010x
      ck$legcol <- TRUE
1381
    }
1382
  }
138333x
  seg[c("dmat", "lc")] <- lapply(seg[c("dmat", "lc")], t)
138433x
  seg$prat <- if (missing(prat) && ck$legcol) {
138510x
    lw <- max(.4, if (ck$legt) strwidth(lega$title, "i"), strwidth(ptxt$leg, "i") / if (seg$ll > 1) 1.3 else 1.7) +
138610x
      if (all(seg$dim == 1)) .5 else .2
138710x
    fw <- (dev.size(units = "in")[1] - lw) / seg$dim[2]
138810x
    c(fw, max(fw / 10, lw))
1389
  } else {
139023x
    prat
1391
  }
139233x
  op <- list(
139333x
    oma = c(
139433x
      sum(is.character(note) && note != "", ck$lx) + .15, ck$ly * .9,
139533x
      max(sum((main != "") * 1.8 + if (sum(seg$dim) > 2) .5 else 0, ck$sud), 1), .5
1396
    ),
139733x
    mar = c(
139833x
      if (ck$lx) 2 else 1.5, if (ck$ly) 3 else 2.4, (ck$sud && (ck$su || ck$c)) *
139933x
        ifelse(seg$ll > 1, 2, 0) + (ck$sub && sum(seg$dim) > 2) * 1.3, 0
1400
    ),
140133x
    mgp = c(3, .3, 0),
140233x
    font.main = 1,
140333x
    font.lab = 2,
140433x
    cex.main = 1,
140533x
    cex.lab = 1,
140633x
    cex.axis = 1,
140733x
    tcl = -.2,
140833x
    pch = 19,
140933x
    xpd = NA
1410
  )
141133x
  if (length(pdo) != 0) {
1412!
    if (any(cpdo <- (npdo <- names(pdo)) %in% names(dop))) {
1413!
      ck$mai <- "mai" %in% npdo
1414!
      op[npdo[cpdo]] <- pdo[cpdo]
1415!
      if ("font.sub" %in% names(op)) op$font.main <- op$font.sub
1416!
      if ("cex.sub" %in% names(op)) op$cex.main <- op$cex.sub
1417!
      if ("col.sub" %in% names(op)) op$col.main <- op$col.sub
1418
    }
1419!
    pdo <- pdo[!cpdo]
1420
  }
142133x
  if (!"horiz" %in% names(pdo) && !"ncol" %in% names(leg.args)) lega$ncol <- 1
142233x
  if (length(pdo) != 0) {
1423!
    if (any(cpdo <- (npdo %in% names(formals(legend)) & !npdo %in% names(leg.args)))) lega[npdo[cpdo]] <- pdo[cpdo]
1424!
    if (any(!cpdo)) {
1425!
      warning("unused argument", if (sum(!cpdo) == 1) ": " else "s: ",
1426!
        paste(names(pdo)[!cpdo], collapse = ", "),
1427!
        call. = FALSE
1428
      )
1429
    }
1430
  }
143133x
  expand_color_code <- function(e) {
1432363x
    if (is.character(e) && all(grepl("^#[0-9a-f]{3}$", e, TRUE))) paste0(e, substring(e, 2)) else e
1433
  }
143433x
  pdo <- lapply(pdo, expand_color_code)
143533x
  op <- lapply(op, expand_color_code)
143633x
  if (dark) {
1437!
    op$fg <- op$col <- op$col.axis <- op$col.main <- op$col.sub <- op$col.sub <- "white"
1438!
    if (is.null(op$bg) && par("bg") == "white") warning("foreground and background are both white")
1439
  }
144033x
  par(op)
144133x
  on.exit(par(dop))
144233x
  layout(seg$dmat, c(rep.int(seg$prat[1], seg$dim[2]), if (ck$legcol) seg$prat[if (length(seg$prat) > 1) 2 else 1]))
144333x
  success <- FALSE
144433x
  ck$scol <- "scols" %in% names(seg)
144533x
  for (i in names(cdat)) {
144653x
    tryCatch(
1447
      {
1448
        # plotting
144953x
        cl <- (if ("list" %in% class(cdat[[i]])) vapply(cdat[[i]], NROW, 0) else nrow(cdat[[i]])) > 0
145053x
        if (any(!cl)) {
1451!
          cdat[[i]] <- cdat[[i]][cl]
1452!
          if (length(cdat[[i]]) == 0) next
1453
        }
14541x
        if (ck$scol) seg$cols <- seg$lcols <- seg$scols[[i]]
145553x
        cl <- strsplit(i, ".^^.", fixed = TRUE)[[1]]
145653x
        ptxt$sub <- if (is.character(sub)) {
1457!
          sub
145853x
        } else if (ck$sub) {
145952x
          if (seg$ll > 1 || (!missing(ndisp) && ndisp)) {
146030x
            paste0(
146130x
              if (seg$f1$e) {
146230x
                paste0(
146330x
                  if (lvn || (ck$mlvn && grepl("^[0-9]", cl[1]))) paste0(ptxt$bet[1], ": "), cl[1],
146430x
                  if (seg$f2$e) paste0(", ", if (lvn || (ck$mlvn && grepl("^[0-9]", cl[2]))) paste0(ptxt$bet[2], ": "), cl[2])
1465
                )
146630x
              }, if ((length(names(cdat)) > 1 || !missing(ndisp)) && ndisp) paste(", n =", seg$n[i])
1467
            )
1468
          } else {
1469
            ""
1470
          }
1471
        }
147253x
        if (!is.null(sort) && ck$t != 2 && any(class(if (seg$by$e) cdat[[i]][[1]][, "x"] else cdat[[i]][, "x"]) %in%
147353x
          c("factor", "character"))) {
14741x
          nsl <- grepl("^[Ff]", as.character(sort))
14751x
          sdir <- grepl("^[DdTt]", as.character(sort))
14761x
          td <- if (seg$by$e) do.call(rbind, cdat[[i]]) else cdat[[i]]
14771x
          td[, "x"] <- as.character(td[, "x"])
14781x
          cdat[[i]] <- do.call(rbind, lapply(
14791x
            if (nsl) {
14801x
              lvs(td[, "x"])
1481
            } else {
1482!
              names(sort(vapply(split(td[, "y"], td[, "x"]), mean, 0, na.rm = TRUE), sdir))
1483
            },
14841x
            function(l) td[td[, "x"] == l, , drop = FALSE]
1485
          ))
14861x
          seg$x$l <- ptxt$l.x <- lvs(cdat[[i]][, "x"])
14871x
          cdat[[i]][, "x"] <- factor(cdat[[i]][, "x"], seg$x$l)
1488!
          if (seg$by$e) cdat[[i]] <- split(cdat[[i]], cdat[[i]][, "by"])
1489
        }
149053x
        if (ck$t == 1) {
1491
          # bar and line
149220x
          flipped <- FALSE
149320x
          if (missing(byx) && ck$mv && any(vapply(cdat[[i]], function(d) {
1494!
            any(vapply(
1495!
              split(d$y, as.character(d$x)),
1496!
              function(dl) if (length(dl) == 1) 0 else var(dl), 0
1497!
            ) == 0)
149820x
          }, TRUE))) {
1499!
            byx <- FALSE
1500
          }
150120x
          if (byx && lim < Inf && seg$by$e && (is.list(cdat[[i]]) && length(cdat[[i]]) > 1)) {
150214x
            flipped <- TRUE
150314x
            cdat[[i]] <- do.call(rbind, cdat[[i]])
150414x
            cdat[[i]][c("x", "by")] <- cdat[[i]][c("by", "x")]
1505!
            if (is.numeric(cdat[[i]]$x)) cdat[[i]]$x <- as.character(cdat[[i]]$x)
150614x
            cdat[[i]] <- split(cdat[[i]], cdat[[i]]$by)[lvs(cdat[[i]]$by)]
1507
          }
150820x
          dl <- if (cl <- "list" %in% class(cdat[[1]])) length(cdat[[i]]) else 1
150920x
          mot <- paste0("y~0+", paste(names(if (cl) cdat[[i]][[1]] else cdat[[i]])[c(2, cvar)], collapse = "+"))
151020x
          m <- pe <- ne <- matrix(NA, seg$by$ll, max(c(1, length(seg$x$l))), dimnames = list(seg$by$l, seg$x$l))
151114x
          if (flipped) m <- pe <- ne <- t(m)
151220x
          rn <- if (nrow(m) == 1) 1 else rownames(m)
151320x
          cn <- if (seg$by$e && flipped) seg$by$l else colnames(m)
151420x
          for (l in seq_len(dl)) {
151534x
            ri <- rn[l]
151634x
            td <- if (cl) cdat[[i]][[ri]] else cdat[[i]]
1517!
            if (is.null(td)) next
151834x
            if (nrow(td) > 1 && length(unique(td$x)) > 1) {
151934x
              mo <- lm(mot, data = td)
152034x
              ccn <- sub("^x", "", names(mo$coef))
152134x
              sus <- which(ccn %in% cn)
152234x
              su <- ccn[sus]
152334x
              m[ri, su] <- mo$coef[sus]
152434x
              if (nrow(td) > 2 && anyDuplicated(td$x)) {
152533x
                if (ck$e) {
152633x
                  e <- suppressWarnings(summary(update(mo, ~ . - 0))$coef[sus, 2])
152733x
                  e <- e[c(2, seq_along(e)[-1])]
152833x
                  pe[ri, su] <- m[l, su] + e
152933x
                  ne[ri, su] <- m[l, su] - e
1530
                } else {
1531!
                  e <- confint(mo)[sus, ]
1532!
                  pe[ri, su] <- e[, 2]
1533!
                  ne[ri, su] <- e[, 1]
1534
                }
1535
              }
1536
            } else {
1537!
              if (nrow(td) == 0) next
1538!
              mo <- lapply(split(td, td["x"]), function(s) if (nrow(s) == 0) NA else mean(s[is.finite(s[, "y"]), "y"]))
1539!
              m[ri, ] <- unlist(mo[colnames(m)])
1540
            }
1541
          }
154220x
          re <- if (flipped) list(m = t(m), ne = t(ne), pe = t(pe)) else list(m = m, ne = ne, pe = pe)
154320x
          if (ck$ltm && all(apply(is.na(re$m), 2, any))) {
1544!
            drop["x"] <- FALSE
1545!
            line.type <- "b"
1546
          }
154720x
          dx <- !apply(is.na(re$m), 2, all)
154820x
          if (drop["x"]) re <- lapply(re, function(s) s[, dx, drop = FALSE])
154920x
          m <- re$m
155020x
          ne <- re$ne
155120x
          pe <- re$pe
1552!
          if (all(mna <- is.na(m))) next
155320x
          re <- lapply(re, function(s) {
155460x
            na <- is.na(s)
155560x
            s[na] <- m[na]
155660x
            s[!mna]
1557
          })
155819x
          if (ck$el) ck$el <- all(round(re$m - re$ne, 8) != 0)
155920x
          lb <- min(re$m) - if (!ck$el) round((max(re$m) - min(re$m)) / 10) else max(abs(re$m - re$ne)) * 1.2
15602x
          if (ck$b && !ck$el) lb <- lb - (max(re$m) - min(re$m)) * .1
156120x
          dm <- dim(m)
156220x
          ylim <- if (missing(myl)) c(lb, max(re$m) + if (ck$el) max(abs(re$m - re$pe)) else 0) else myl
156320x
          if (ck$leg == 2 && ck$lp) {
15643x
            if (!seg$by$e && ncol(m) == 2) {
15651x
              lega$x <- "top"
1566
            } else {
15672x
              lega$x <- apply(m, 2, function(r) {
15684x
                na <- !is.na(r)
1569!
                if (any(na)) max(r[na]) else -Inf
1570
              })
15712x
              stw <- ncol(m)
15722x
              oyl <- if (stw %% 2) 3 else 2
15732x
              lega$x <- c("topleft", "top", "topright")[if (oyl == 2) -2 else 1:3][which.min(vapply(split(lega$x, rep(seq_len(oyl),
15742x
                each = stw / oyl
15752x
              )[seq_len(stw)]), mean, 0, na.rm = TRUE))]
1576!
              if (is.na(lega$x)) lega$x <- "topright"
1577
            }
1578
          }
1579!
          if (any(is.na(ylim))) next
158020x
          oyl <- axTicks(2, c(ylim[1], ylim[2], par("yaxp")[3]))
158120x
          rn <- if (nrow(m) == 1) colnames(m) else rownames(m)
158220x
          colnames(m) <- if (drop["x"] && sum(dx) == ncol(m)) ptxt$l.x[dx] else ptxt$l.x
158320x
          stw <- strwidth(colnames(m), "i")
158420x
          if ((missing(xlas) || xlas > 1) && sum(stw) > par("fin")[1] - sum(par("omi")[c(2, 4)]) - dm[2] * .1 && par("fin")[1] > 2.5) {
1585!
            xlas <- 3
1586!
            if (missing(mxl)) mxl <- c(1, dm[2])
1587!
            mh <- c(par("fin")[2] / 2, max(stw))
1588!
            par(mai = if (ck$mai) op$mai else c(min(mh) + .25, par("mai")[-1]))
1589!
            if (mh[1] < mh[2] && missing(labels.trim)) {
1590!
              mh <- round(mh[1] / .1)
1591!
              n <- colnames(m)
1592!
              ln <- nchar(n) > mh
1593!
              colnames(m)[ln] <- sub("$", "...", strtrim(n[ln], mh))
1594
            }
1595
          }
15962x
          if (min(re$ne, na.rm = TRUE) >= 0) autori <- FALSE
159720x
          rck <- !is.list(seg$cols) && all(rn %in% names(seg$cols))
1598!
          if (rck && length(seg$cols) < dm[1]) seg$cols <- rep_len(seg$cols, dm[1])
15991x
          if (!rck && ck$ltm && !ck$el) line.type <- "b"
160020x
          if (ck$b) {
16017x
            if (autori) {
16025x
              a <- if (missing(myl)) lb else myl[1]
16035x
              a <- a * -1
16045x
              m <- m + a
16055x
              ne <- ne + a
16065x
              pe <- pe + a
16075x
              ayl <- oyl + a
16085x
              aj <- lapply(re, "+", a)
16095x
              ylim <- if (missing(myl)) {
16105x
                if (!ck$el) {
1611!
                  ylim + a
1612
                } else {
16135x
                  c(
16145x
                    min(aj$m) - max(abs(aj$m - aj$ne)) * 1.2,
16155x
                    max(aj$m) + max(abs(aj$m - aj$pe)) * if (ck$leg == 2 && seg$by$ll > 1) seg$by$ll^.3 + .7 else 1.2
1616
                  )
1617
                }
1618
              } else {
1619!
                myl + a
1620
              }
1621
            }
16224x
            if (dm[1] != 1) rownames(m) <- ptxt$l.by[rn]
16237x
            lega[c("lwd", "lty")] <- NULL
16247x
            lega[c("pch", "pt.cex", "x.intersp", "y.intersp", "adj")] <- list(15, 2, 1, 1.2, c(0, .35))
16257x
            p <- barplot(m,
16267x
              beside = TRUE, col = if (rck) seg$cols[rn] else seg$cols, axes = FALSE, axisnames = FALSE,
16277x
              border = NA, ylab = NA, xlab = NA, ylim = ylim, main = if (ck$sub) ptxt$sub else NA,
16287x
              xpd = if ("xpd" %in% names(pdo)) pdo$xpd else if (autori) NA else FALSE
1629
            )
1630
          } else {
163113x
            p <- matrix(rep.int(seq_len(dm[2]), dm[1]), nrow = dm[1], byrow = TRUE)
163213x
            plot(NA,
163313x
              ylim = ylim, xlim = if (missing(mxl)) c(1 - stw[1] / 3, dm[2] + stw[length(stw)] / 3) else mxl, ylab = NA, xlab = NA,
163413x
              main = if (ck$sub) ptxt$sub else NA, axes = FALSE
1635
            )
163613x
            for (a in if (dm[1] == 1) 1 else if (all(rn %in% names(seg$cols))) rn else seq_len(dm[1])) {
163723x
              graphics::lines(m[a, ], col = seg$cols[[a]], lty = seg$lty[[a]], lwd = seg$lwd[[a]], type = line.type)
1638
            }
1639
          }
1640!
          if (ck$ileg) lega$legend <- rn
164120x
          if (xaxis) axis(1, colMeans(p), colnames(m), FALSE, las = xlas, cex = par("cex.axis"), fg = par("col.axis"))
164220x
          a2a <- list(2, las = ylas, cex = par("cex.axis"), fg = par("col.axis"))
164320x
          if (ck$b && autori) {
16445x
            a2a$at <- ayl
16455x
            a2a$labels <- formatC(oyl, 2, format = "f")
1646
          }
164720x
          if (yaxis) do.call(axis, a2a)
164820x
          if (ck$el) {
164918x
            te <- round(Reduce("-", list(ne, pe)), 8)
165018x
            te[is.na(te)] <- 0
165118x
            te <- te == 0
1652!
            if (any(te)) ne[te] <- pe[te] <- NA
165318x
            arrows(p, ne, p, pe, lwd = error.lwd, col = error.color, angle = 90, code = 3, length = .05)
1654
          }
165533x
        } else if (ck$t == 2) {
1656
          # density
1657!
          if (!is.list(density.args)) density.args <- list()
165814x
          fdan <- names(formals(stats::density.default))
165914x
          dan <- names(density.args)
166014x
          if (any(mdan <- !dan %in% fdan)) {
1661!
            warning(paste("unused density argument(s):", paste(dan[mdan], collapse = ", ")), call. = FALSE)
1662!
            density.args <- density.args[!mdan]
1663
          }
166414x
          density.args$give.Rkern <- FALSE
166514x
          if (!missing(mxl)) {
1666!
            if (!"from" %in% dan) density.args$from <- mxl[1]
1667!
            if (!"to" %in% dan) density.args$to <- mxl[2]
1668
          }
166910x
          if (!"n" %in% dan) density.args$n <- 512
167014x
          n <- density.args$n
167114x
          m <- list()
167214x
          dl <- if (cl <- "list" %in% class(cdat[[i]])) length(cdat[[i]]) else 1
167314x
          rnl <- logical(dl)
167414x
          rn <- if (is.data.frame(cdat[[i]])) names(ptxt$l.by) else names(cdat[[i]])
167514x
          dx <- dy <- numeric(n * seg$by$ll)
167614x
          for (l in seq_len(dl)) {
167722x
            tryCatch(
1678
              {
167922x
                density.args$x <- (if (cl) cdat[[i]][[l]] else cdat[[i]])[, "y"]
168022x
                m[[l]] <- do.call(stats::density, density.args)
168122x
                dx[seq_len(n) + n * (l - 1)] <- m[[l]]$x
168222x
                dy[seq_len(n) + n * (l - 1)] <- m[[l]]$y
168322x
                rnl[l] <- TRUE
1684
              },
168522x
              error = function(e) NULL
1686
            )
1687
          }
168814x
          names(m) <- rn <- rn[rnl]
168914x
          if (seg$by$ll > 1 || (ck$polyo && ck$poly)) {
16908x
            plot(NA,
16918x
              xlim = if (missing(mxl)) range(c(dx, dx)) else mxl, ylim = if (missing(myl)) c(0, max(dy)) else myl,
16928x
              main = if (ck$sub) ptxt$sub else NA, ylab = NA, xlab = NA, axes = FALSE, xpd = if ("xpd" %in% names(pdo)) pdo$xpd else FALSE
1693
            )
16948x
            for (l in if (seg$by$ll > 1 && all(rn %in% names(seg$cols))) rn else seq_along(m)) {
169516x
              if (ck$poly) polygon(m[[l]], col = adjustcolor(seg$cols[[l]], density.opacity), border = NA)
169616x
              if (!is.logical(lines) || lines) graphics::lines(m[[l]], col = seg$cols[[l]], lwd = seg$lwd[[l]], lty = seg$lty[[l]])
1697
            }
1698!
            if (ck$ileg) lega$legend <- rn
1699
          } else {
17006x
            col <- if (length(seg$lcols) > 2) "#555555" else seg$lcols[1]
17016x
            if (ck$leg) {
1702!
              lega[c("lwd", "lty")] <- NULL
1703!
              lega[c("pch", "pt.cex", "x.intersp", "y.intersp", "adj")] <- list(15, 2, 1, 1.2, c(0, .35))
1704
            }
17056x
            y <- (if (cl) cdat[[i]][[1]] else cdat[[i]])[, "y"]
17066x
            hp <- hist(y, breaks, plot = FALSE)
17076x
            if (ck$cb && length(seg$cols) == nr) {
1708!
              nb <- length(hp$counts)
1709!
              seg$cols <- vapply(split(seg$cols[order(y)], sort(rep_len(seq_len(nb), nr))), csf, "")
1710!
              if (!ckn) seg$cols <- adjustcolor(seg$cols, 1, color.offset, color.offset, color.offset)
17116x
            } else if (!color.lock && (ck$co || length(seg$cols) == 1)) {
17126x
              seg$cols[2] <- adjustcolor(seg$cols[1], 1, color.offset, color.offset, color.offset)
1713
            }
17146x
            hist(
17156x
              y, breaks, FALSE,
17166x
              border = if ("border" %in% names(pdo)) pdo$border else par("bg"), main = if (ck$sub) ptxt$sub else NA,
17176x
              ylab = NA, xlab = NA, axes = FALSE, col = if (length(seg$cols) == 2) seg$cols[2] else seg$cols,
17186x
              xlim = if (missing(mxl)) range(hp$breaks) else mxl,
17196x
              ylim = if (missing(myl)) c(0, max(c(dy, hp$density))) else myl
1720
            )
17216x
            if (!is.logical(lines) || lines) {
17226x
              graphics::lines(m[[1]], col = col, lwd = lwd, xpd = if ("xpd" %in% names(pdo)) {
1723!
                pdo$xpd
1724
              } else {
17256x
                FALSE
1726
              })
1727
            }
1728
          }
17292x
          if (ck$lp && ck$leg == 2) lega$x <- if (mean(dx) > mean(range(dx))) "topleft" else "topright"
173014x
          if (xaxis) axis(1, las = xlas, cex = par("cex.axis"), fg = par("col.axis"))
173114x
          if (yaxis) axis(2, las = ylas, cex = par("cex.axis"), fg = par("col.axis"))
1732
        } else {
1733
          # scatter
173419x
          dl <- if (cl <- "list" %in% class(cdat[[i]])) length(cdat[[i]]) else 1
173519x
          rn <- if (is.data.frame(cdat[[i]])) seg$by$l else names(cdat[[i]])
173619x
          td <- if (cl) do.call(rbind, cdat[[i]]) else cdat[[i]]
173719x
          cx <- td[, "x"]
173819x
          cy <- td[, "y"]
173919x
          xch <- if (is.numeric(cx) || is.logical(cx)) cx else as.numeric(factor(cx))
174019x
          a2a <- list(cex = par("cex.axis"), fg = par("col.axis"))
174119x
          if (length(ptxt$l.x) != 0) {
1742!
            a2a$tick <- FALSE
1743!
            a2a$at <- seq_along(ptxt$l.x)
1744!
            a2a$labels <- ptxt$l.x
1745!
            if (missing(xlas) || xlas > 1) {
1746!
              xlas <- 3
1747!
              par(mai = if (ck$mai) {
1748!
                op$mai
1749
              } else {
1750!
                c(
1751!
                  min(c(par("fin")[2] / 2, max(strwidth(ptxt$l.x, "i")))) + .25, par("mai")[-1]
1752
                )
1753
              })
1754
            }
1755
          }
175619x
          plot(
175719x
            NA,
175819x
            xlim = if (missing(mxl)) range(xch, na.rm = TRUE) else mxl,
175919x
            ylim = if (missing(myl)) {
176019x
              c(min(cy, na.rm = TRUE), max(cy, na.rm = TRUE) + max(cy, na.rm = TRUE) *
176119x
                if (ck$leg == 1 && seg$by$ll < lim) seg$by$ll / 20 else 0)
1762
            } else {
1763!
              myl
1764
            },
176519x
            main = if (ck$sub) ptxt$sub else NA, ylab = NA, xlab = NA, axes = FALSE
1766
          )
176719x
          if (yaxis) {
176819x
            do.call(axis, c(list(2, las = ylas), c(
176919x
              a2a[c("cex", "fg")],
177019x
              if ("yax" %in% names(txt)) list(at = seq_along(txt$yax), labels = txt$yax, tick = FALSE)
1771
            )))
1772
          }
177319x
          if (xaxis) do.call(axis, c(list(1, las = xlas), a2a))
177419x
          if (ck$leg > 1) {
17755x
            up <- xch[cy >= quantile(cy, na.rm = TRUE)[4]]
17765x
            mr <- quantile(xch, na.rm = TRUE)
17775x
            if (ck$lp) lega$x <- if (sum(up < mr[2]) > sum(up > mr[4])) "topright" else "topleft"
1778!
            if (ck$ileg) lega$legend <- rn
1779
          }
178019x
          padj <- if (color.lock || ck$cb || (missing(color.offset) && !ck$ltck)) 1 else color.offset
178119x
          ckcn <- all(rn %in% names(seg$cols))
178219x
          ckln <- all(rn %in% names(seg$lcols))
178319x
          if (!ckln) {
17844x
            if (ckcn) {
1785!
              seg$lcols <- seg$cols
1786
            } else {
17874x
              seg$lcols[] <- if (opacity != 1) {
1788!
                adjustcolor("#555555", opacity)
1789
              } else {
17904x
                "#555555"
1791
              }
1792
            }
1793
          }
179419x
          lwd <- rep_len(if (is.numeric(lwd)) lwd else 2, dl)
179519x
          for (l in if (ckcn) rn else seq_len(dl)) {
179634x
            td <- if (cl) cdat[[i]][[l]] else cdat[[i]]
1797!
            if (is.null(td)) next
179834x
            x <- td[, "x"]
179934x
            y <- td[, "y"]
180034x
            col <- if (ckcn) seg$cols[[l]] else seg$cols
180132x
            if (opacity != 1 || padj != 1) col <- adjustcolor(col, opacity, padj, padj, padj)
180234x
            if (points && points.first) points(x, y, col = col, cex = cex["points"])
180334x
            if (ck$ltck) {
180434x
              lt <- if (ck$ltco == "pr" && length(unique(y)) != 2) "li" else ck$ltco
180534x
              fit <- if (lt == "e") {
1806!
                y
1807
              } else {
180834x
                tryCatch(
1809
                  {
181034x
                    if (ck$c) {
1811!
                      lm(y ~ x + as.matrix(td[, cvar, drop = FALSE]))$fitted
181234x
                    } else if (lt == "pr") {
1813!
                      yr <- range(y)
1814!
                      y <- factor(y, labels = c(0, 1))
1815!
                      fit <- predict(glm(y ~ x, binomial))
1816!
                      fit <- exp(fit) / (1 + exp(fit))
1817!
                      if (!all(yr == c(0, 1))) fit <- (fit - mean(fit)) * (yr[2] - yr[1]) + mean(yr)
1818!
                      if (max(fit) > yr[2]) fit - (max(fit) - yr[2]) else fit
1819
                    } else {
182034x
                      predict(switch(lt,
182134x
                        li = lm,
182234x
                        lo = loess,
182334x
                        sm = smooth.spline
182434x
                      )(y ~ x))
1825
                    }
1826
                  },
182734x
                  error = function(e) {
1828!
                    warning("error estimating line: ", e$message, call. = FALSE)
1829!
                    NULL
1830
                  }
1831
                )
1832
              }
183334x
              if (!is.null(fit)) {
183434x
                if (lt == "e") {
1835!
                  xo <- x
183634x
                } else if (lt == "sm") {
1837!
                  xo <- fit$x
1838!
                  fit <- fit$y
1839
                } else {
184034x
                  or <- order(x)
184134x
                  xo <- x[or]
184234x
                  fit <- fit[or]
1843
                }
184434x
                graphics::lines(xo, fit, col = seg$lcols[[l]], lty = seg$lty[[l]], lwd = seg$lwd[[l]])
1845
              }
1846
            }
1847!
            if (points && !points.first) points(x, y, col = col, cex = cex["points"])
1848
          }
1849
        }
185053x
        if (ck$leg == 2) {
185110x
          if (ck$lpm) {
1852!
            message("click to place the legend")
1853!
            lega[c("x", "y")] <- locator(1)
1854!
            if (is.null(lega$x)) {
1855!
              warning("placing the legend with locator(1) failed")
1856!
              lega$y <- NULL
1857!
              lega$x <- if (seg$ll > 1) "topright" else "right"
1858
            }
1859
          }
186010x
          tf <- par("font")
186110x
          par(font = font["leg.title"])
186210x
          do.call(legend, lega)
186310x
          par(font = tf)
1864
        }
186553x
        success <- TRUE
186653x
        if (!missing(add)) {
18671x
          add_attempt <- tryCatch(eval(substitute(add), fdat), error = function(e) list(failed = TRUE))
18681x
          if (is.list(add_attempt) && isTRUE(add_attempt$failed)) {
1869!
            tryCatch(
1870!
              eval(substitute(add), parent.frame(1)),
1871!
              error = function(e) warning("error from add: ", e$message, call. = FALSE)
1872
            )
1873
          }
1874
        }
1875
      },
187653x
      error = function(e) {
1877!
        dev.off()
1878!
        stop(e)
1879
      }
1880
    )
1881
  }
1882!
  if (!success) stop("failed to make any plots with the current input", call. = FALSE)
188333x
  if (ck$leg == 1) {
188410x
    if (all(par("mfg")[1:2] != 0)) {
188510x
      plot.new()
18861x
      if (ck$b) lega[c("pch", "pt.cex", "x.intersp", "y.intersp", "adj")] <- list(15, 2, 1, 1.2, c(0, .35))
188710x
      if (ck$lpm) {
1888!
        message("click to place the legend")
1889!
        lega[c("x", "y")] <- locator(1)
1890!
        if (is.null(lega$x)) {
1891!
          warning("placing the legend with locator(1) failed")
1892!
          lega$y <- NULL
1893!
          lega$x <- if (seg$ll > 1) "topright" else "right"
1894
        }
1895
      }
189610x
      tf <- par("font")
189710x
      par(font = font["leg.title"])
189810x
      do.call(legend, lega)
189910x
      par(font = tf)
1900
    } else {
1901!
      warning("legend positioning failed", call. = FALSE)
1902
    }
1903
  }
190433x
  if (ck$sud && any(ck$su, ck$c, is.character(sud))) {
1905!
    mtext(
1906!
      if (is.character(sud)) {
1907!
        sud
1908
      } else {
1909!
        gsub(", (?=[A-z0-9 ]+$)", ifelse(length(ptxt$cov) > 2, ", & ", " & "), gsub("^ | $", "", paste0(if (ck$su) {
1910!
          paste("Subset:", paste0(txt$su[1], if (length(txt$su) != 1) "..."))
1911!
        }, if (ck$su && ck$c) ", ", if (ck$c) {
1912!
          paste(if (ck$t == 1) "Covariates:" else "Line adjustment:", paste(ptxt$cov, collapse = ", "))
1913!
        })), TRUE, TRUE)
1914
      },
1915!
      3, 0, TRUE,
1916!
      cex = cex["sud"], font = font["sud"]
1917
    )
1918
  }
191933x
  mtext(main, 3, if (ck$sud) 1.5 else .5, TRUE, cex = cex["title"], font = font["title"])
192033x
  mtext(ylab, 2, -.2, TRUE, cex = par("cex.lab"), font = par("font.lab"))
192133x
  mtext(xlab, 1, 0, TRUE, cex = par("cex.lab"), font = par("font.lab"))
192222x
  if (is.character(note)) mtext(note, 1, ck$lx, TRUE, adj = if (ck$ly) 0 else .01, font = font["note"], cex = cex["note"])
192333x
  if (save || (missing(save) && any(!missing(format), !missing(file.name), !missing(dims)))) {
19241x
    tryCatch(
1925
      {
19261x
        if (is.character(format) || is.name(format)) {
19271x
          t <- as.character(format)
19281x
          format <- eval(parse(text = t))
1929
        } else {
1930!
          t <- deparse(substitute(format))
1931
        }
19321x
        if (is.function(format)) t <- sub("^[^:]*::", "", t)
19331x
        tt <- if (any(grepl("cairo", t, TRUE))) {
1934!
          paste0(".", tolower(strsplit(t, "_|Cairo")[[1]][2]))
19351x
        } else if (t == "postscript") ".ps" else paste0(".", t)
1936!
        if (missing(dims) && grepl("jpeg|png|tiff|bmp|bit", t, TRUE)) dims <- dev.size(units = "px")
19371x
        fn <- paste0(if (main == "" || !missing(file.name)) {
19381x
          sub("\\.[^.]+$", "", file.name)
1939
        } else {
1940!
          gsub("\\s+", "_", gsub("^ +| +$|  ", "", main))
19411x
        }, tt)
19421x
        dev.copy(format, fn, width = dims[1], height = dims[2])
19431x
        dev.off()
1944!
        if (file.exists(fn)) message("image saved: ", fn) else warning("failed to save image")
1945
      },
19461x
      error = function(e) warning("unable to save image: ", e$message, call. = FALSE)
1947
    )
1948
  }
194933x
  invisible(list(dat = dat, cdat = cdat, txt = txt, ptxt = ptxt, seg = seg, ck = ck, lega = lega, fmod = fmod))
1950
}
1
#' splot color average
2
#'
3
#' Calculates the average of a set of colors, returning its Hex code.
4
#' @param ... color codes or names as characters.
5
#' @return The calculated color code.
6
#' @examples
7
#' # average of red and blue
8
#' plot(
9
#'   1:3, numeric(3),
10
#'   pch = 15, cex = 20, xlim = c(0, 4),
11
#'   col = c("red", splot.colormean("red", "blue"), "blue")
12
#' )
13
#'
14
#' # average of a set
15
#' x <- rnorm(100)
16
#' set <- splot.color(x, method = "related")
17
#' splot(
18
#'   x ~ rnorm(100),
19
#'   colors = set,
20
#'   add = points(0, 0, pch = 15, cex = 10, col = splot.colormean(set))
21
#' )
22
#' @export
23
24
splot.colormean <- function(...) {
251x
  hdc <- c(0:9, LETTERS[1:6])
261x
  hdc <- outer(hdc, hdc, paste0)
271x
  s <- seq_len(16)
281x
  ccs <- adjustcolor(unlist(list(...), use.names = FALSE))
291x
  paste(c("#", apply(Reduce("+", lapply(ccs, function(cc) {
302x
    cc <- strsplit(cc, "")[[1]][2:7]
312x
    cc <- paste0(cc[c(TRUE, FALSE)], cc[c(FALSE, TRUE)])
322x
    vapply(cc, function(c) which(hdc == c, TRUE), numeric(2))
331x
  })) / length(ccs), 2, function(cc) {
343x
    hdc[which.min(abs(s - cc[1])), which.min(abs(s - cc[2]))]
351x
  })), collapse = "")
36
}
1
#' splot color contrast ratio
2
#'
3
#' Calculates the color contrast ratio between two sets of colors, as defined by the
4
#' \href{https://www.w3.org/TR/WCAG20/#contrast-ratiodef}{World Wide Web Consortium}.
5
#' @param color,background A character vector of colors, or a matrix with RGB values across rows.
6
#' @param plot Logical; if \code{FALSE}, will not plot the results.
7
#' @return A list with entries for \code{ratio} (contrast ratio),
8
#' \code{AA} (ratios of at least 4.5), and \code{AAA} (ratios of at least 7).
9
#' Each entry contains a matrix with colors in rows and backgrounds in columns.
10
#' @examples
11
#' # check colors against dark and light backgrounds
12
#' splot.colorcontrast(c("#FF0000", "#00FF00", "#0000FF"), c("black", "white"))
13
#'
14
#' # check contrast between colors
15
#' splot.colorcontrast(c("red", "green", "blue"), c("red", "green", "blue"))
16
#'
17
#' # see when shades of a color cross thresholds on a given background
18
#' splot.colorcontrast(splot.color(1:10, seed = "#a388b5"), "#101010")
19
#' @export
20
21
splot.colorcontrast <- function(color, background = "#ffffff", plot = TRUE) {
221x
  oc <- color
231x
  ob <- background
241x
  adj <- c(0.2126, 0.7152, 0.0722)
251x
  if (is.character(color)) color <- col2rgb(color)
26!
  if (is.null(dim(color))) color <- matrix(color, 3)
271x
  if (is.character(background)) background <- col2rgb(background)
28!
  if (is.null(dim(background))) background <- matrix(background, 3)
291x
  color <- color / 255
301x
  su <- color <= .03928
31!
  if (any(su)) color[su] <- color[su] / 12.92
321x
  color[!su] <- ((color[!su] + .055) / 1.055)^2.4
331x
  color <- colSums(color * adj)
341x
  background <- background / 255
351x
  su <- background <= .03928
36!
  if (any(su)) background[su] <- background[su] / 12.92
371x
  background[!su] <- ((background[!su] + .055) / 1.055)^2.4
381x
  background <- colSums(background * adj)
391x
  r <- vapply(background, function(bg) {
401x
    su <- bg > color
411x
    color[su] <- (bg + .05) / (color[su] + .05)
421x
    color[!su] <- (color[!su] + .05) / (bg + .05)
431x
    color
441x
  }, color)
451x
  if (is.null(dimnames(r))) r <- matrix(r, length(color))
461x
  rownames(r) <- if (is.character(oc)) oc else paste0("color_", seq_along(color))
471x
  colnames(r) <- if (is.character(ob)) ob else paste0("background_", seq_along(background))
481x
  if (plot) {
491x
    data <- data.frame(
501x
      Contrast = as.numeric(r),
511x
      Background = rep(colnames(r), each = nrow(r)),
521x
      Color = rep(rownames(r), ncol(r))
53
    )
541x
    splot(
551x
      Contrast ~ Color, data,
561x
      between = "Background",
571x
      type = "bar", title = FALSE, colors = data$Color, ndisp = FALSE, sort = FALSE,
581x
      add = {
591x
        abline(h = 4.5, col = "#a52600", xpd = FALSE)
601x
        abline(h = 7, col = "#0050a5", xpd = FALSE, lty = 2)
61
      },
621x
      note = "The solid red line is the AA threshold, and the dashed blue line is the AAA threshold."
63
    )
64
  }
651x
  list(ratio = r, AA = r >= 4.5, AAA = r >= 7)
66
}
1
#' splot benchmarker
2
#'
3
#' Time one or more expressions over several iteration, then plot the distributions of their times.
4
#' @param ... accepts any number of expressions to be timed. See examples.
5
#' @param runs the number of overall iterations. Increase to stabilize estimates.
6
#' @param runsize the number of times each expression is evaluated within each run. Increase to
7
#'   differentiate estimates (particularly for very fast operations).
8
#' @param cleanup logical; if \code{TRUE}, garbage collection will be performed before each run.
9
#'   Garbage collection greatly increases run time, but may result in more stable timings.
10
#' @param print.names logical; if \code{FALSE}, the entered expressions will be included in the plot
11
#'   as legend names. Otherwise, (and if the number of expressions is over 5 or the length of any
12
#'   expression is over 50 characters) expressions are replaced with numbers corresponding to their
13
#'   entered position.
14
#' @param limit.outliers logical; if \code{TRUE} (default), times over an upper bound for the given
15
#'   expression will be set to that upper bound, removing aberrant extremes.
16
#' @param check_output logical; if \code{TRUE}, the output of each expression is checked with
17
#'   \code{\link[base]{all.equal}} against that of the first. A warning indicates if any are not
18
#'   equal, and results are invisibly returned.
19
#' @param check_args a list of arguments to be passed to \code{\link[base]{all.equal}}, if
20
#'   \code{check_output} is \code{TRUE}.
21
#' @param options a list of options to pass on to splot.
22
#' @return A list:
23
#' \tabular{ll}{
24
#'   plot \tab splot output\cr
25
#'   checks \tab a list of result from all.equal, if \code{check_output} was \code{TRUE}\cr
26
#'   expressions \tab a list of the entered expressions \cr
27
#'   summary \tab a matrix of the printed results \cr
28
#' }
29
#' @examples
30
#' # increase the number of runs for more stable estimates
31
#'
32
#' # compare ways of looping through a vector
33
#' splot.bench(
34
#'   sapply(1:100, "*", 10),
35
#'   mapply("*", 1:100, 10),
36
#'   vapply(1:100, "*", 0, 10),
37
#'   unlist(lapply(1:100, "*", 10)),
38
#'   runs = 20, runsize = 200
39
#' )
40
#'
41
#' # compare ways of setting all but the maximum value of each row in a matrix to 0
42
#' \donttest{
43
#'
44
#' mat <- matrix(c(rep(1, 4), rep(0, 8)), 4, 3)
45
#' splot.bench(
46
#'   t(vapply(seq_len(4), function(r) {
47
#'     mat[r, mat[r, ] < max(mat[r, ])] <- 0
48
#'     mat[r, ]
49
#'   }, numeric(ncol(mat)))),
50
#'   do.call(rbind, lapply(seq_len(4), function(r) {
51
#'     mat[r, mat[r, ] < max(mat[r, ])] <- 0
52
#'     mat[r, ]
53
#'   })),
54
#'   do.call(rbind, lapply(seq_len(4), function(r) {
55
#'     nr <- mat[r, ]
56
#'     nr[nr < max(nr)] <- 0
57
#'     nr
58
#'   })),
59
#'   {
60
#'     nm <- mat
61
#'     for (r in seq_len(4)) {
62
#'       nr <- nm[r, ]
63
#'       nm[r, nr < max(nr)] <- 0
64
#'     }
65
#'     nm
66
#'   },
67
#'   {
68
#'     nm <- mat
69
#'     for (r in seq_len(4)) nm[r, nm[r, ] < max(nm[r, ])] <- 0
70
#'     nm
71
#'   },
72
#'   {
73
#'     nm <- matrix(0, dim(mat)[1], dim(mat)[2])
74
#'     for (r in seq_len(4)) {
75
#'       m <- which.max(mat[r, ])
76
#'       nm[r, m] <- mat[r, m]
77
#'     }
78
#'     nm
79
#'   },
80
#'   {
81
#'     ck <- do.call(rbind, lapply(seq_len(4), function(r) {
82
#'       nr <- mat[r, ]
83
#'       nr < max(nr)
84
#'     }))
85
#'     nm <- mat
86
#'     nm[ck] <- 0
87
#'     nm
88
#'   },
89
#'   t(apply(mat, 1, function(r) {
90
#'     r[r < max(r)] <- 0
91
#'     r
92
#'   })),
93
#'   runs = 50,
94
#'   runsize = 200
95
#' )
96
#' }
97
#' @export
98
99
splot.bench <- function(
100
    ..., runs = 20, runsize = 200, cleanup = FALSE, print.names = FALSE,
101
    limit.outliers = TRUE, check_output = TRUE, check_args = list(), options = list()) {
1021x
  e <- sapply(as.character(substitute(list(...)))[-1], function(t) parse(text = t))
1031x
  e <- e[!duplicated(names(e))]
1041x
  es <- length(e)
105!
  if (!es) stop("no expressions found", call. = FALSE)
1061x
  ne <- names(e)
1071x
  seconds <- matrix(NA, runs, es, dimnames = list(NULL, ne))
1081x
  rs <- seq_len(runsize)
1091x
  ops <- tryCatch(
1101x
    lapply(e, eval, parent.frame(3)),
1111x
    error = function(e) stop("one of your expressions breaks:\n", e, call. = FALSE)
112
  )
1131x
  checks <- if (check_output && length(e) != 1) {
1141x
    if (!"check.attributes" %in% names(check_args)) check_args$check.attributes <- FALSE
1151x
    if (!"check.names" %in% names(check_args)) check_args$check.names <- FALSE
1161x
    lapply(ops[-1], function(r) {
1171x
      tryCatch(
1181x
        do.call(all.equal, c(list(r), list(ops[[1]]), check_args)),
1191x
        error = function(e) FALSE
120
      )
121
    })
122
  } else {
123!
    NULL
124
  }
1251x
  if (!is.null(checks) && !all(vapply(checks, isTRUE, TRUE))) {
126!
    warning(
127!
      "some of your expressions do not seem to have similar results as the first;",
128!
      " see the `checks` output.",
129!
      call. = FALSE
130
    )
131
  }
1321x
  ost <- proc.time()[3]
1331x
  cat("benchmarking", es, "expression(s) in chunks of", runsize, "per run... \nrun 0 of", runs)
1341x
  fun <- function(e) {
13540x
    eval(e, .GlobalEnv)
13640x
    NULL
137
  }
1381x
  for (r in seq_len(runs)) {
13920x
    for (f in sample(seq_len(es))) {
140!
      if (cleanup) gc(FALSE)
14140x
      st <- proc.time()[[3]]
14240x
      for (i in rs) fun(e[[f]])
14340x
      seconds[r, f] <- proc.time()[[3]] - st
144
    }
14520x
    cat("\rrun", r, "of", runs)
146
  }
1471x
  cat("\rfinished", runs, "runs in", round(proc.time()[3] - ost, 2), "seconds       \n\n")
1481x
  cat("expressions:\n\n")
1491x
  icn <- seq_len(es)
1501x
  ne <- gsub("\n", "\n   ", ne, fixed = TRUE)
1511x
  for (i in icn) cat(i, ". ", ne[i], "\n", sep = "")
1521x
  cat("\n")
1531x
  res <- rbind(colSums(seconds), colMeans(seconds))
1541x
  res <- rbind(res, if (min(res[1, ], na.rm = TRUE) == 0) res[1, ] + 1 else res[1, ] / min(res[1, ], na.rm = TRUE))
1551x
  dimnames(res) <- list(c("total time (seconds)", "mean time per run", "times the minimum"), icn)
1561x
  print(round(res, 4))
1571x
  if (!print.names) {
1581x
    if (!missing(print.names) || es > 5 || any(nchar(names(e)) > 50)) {
159!
      colnames(seconds) <- icn
160
    }
161
  }
1621x
  if (limit.outliers) {
1631x
    for (f in seq_len(es)) {
1642x
      qr <- quantile(seconds[, f], c(.25, .75), TRUE)
1652x
      qrc <- qr[2] + (qr[2] - qr[1]) * 1.5
1662x
      seconds[seconds[, f] > qrc, f] <- qrc
167
    }
168
  }
1691x
  if (es == 1 && runs == 1) {
170!
    return(list(plot = NULL, summary = res))
171
  }
1721x
  title <- paste("timing of", runs, "runs of", runsize, "calls each")
1731x
  if (nrow(seconds) == 1) {
174!
    options$x <- colnames(seconds)
175!
    seconds <- seconds[1, ]
176
  }
1771x
  invisible(list(
1781x
    plot = splot(seconds, title = title, labels.filter = FALSE, labels.trim = FALSE, options = options),
1791x
    checks = checks,
1801x
    expressions = as.list(unname(e)),
1811x
    summary = res
182
  ))
183
}

[8]ページ先頭

©2009-2025 Movatter.jp