|
a |
|
b/R/auxiliary.R |
|
|
1 |
#### |
|
|
2 |
# Matrix Operations #### |
|
|
3 |
#### |
|
|
4 |
|
|
|
5 |
getMin <- function(data, ...){ |
|
|
6 |
if(inherits(data, "IterableMatrix")){ |
|
|
7 |
data <- as(data, "dgCMatrix") |
|
|
8 |
} |
|
|
9 |
return(min(data, ...)) |
|
|
10 |
} |
|
|
11 |
|
|
|
12 |
getMax <- function(data, ...){ |
|
|
13 |
if(inherits(data, "IterableMatrix")){ |
|
|
14 |
data <- as(data, "dgCMatrix") |
|
|
15 |
} |
|
|
16 |
return(max(data, ...)) |
|
|
17 |
} |
|
|
18 |
|
|
|
19 |
getRange <- function(data, ...){ |
|
|
20 |
return(c(getMin(data, ...), getMax(data, ...))) |
|
|
21 |
} |
|
|
22 |
|
|
|
23 |
getColQuantiles <- function(data, desiredQuantile){ |
|
|
24 |
if(inherits(data, "IterableMatrix")){ |
|
|
25 |
return(BPCells::colQuantiles(data, probs = desiredQuantile)) |
|
|
26 |
} else { |
|
|
27 |
return(apply(data, 2, function(x) stats::quantile(x, desiredQuantile))) |
|
|
28 |
} |
|
|
29 |
} |
|
|
30 |
|
|
|
31 |
|
|
|
32 |
#### |
|
|
33 |
# Nanostring Auxiliary tools #### |
|
|
34 |
#### |
|
|
35 |
|
|
|
36 |
generate_pkc_lookup <- function (jsons_vec) |
|
|
37 |
{ |
|
|
38 |
lookup_df <- data.frame(RTS_ID = character(), Target = character(), |
|
|
39 |
Module = character(), CodeClass = character(), ProbeID = character(), |
|
|
40 |
GeneID = character(), SystematicName = character(), stringsAsFactors = FALSE) |
|
|
41 |
for (curr_idx in seq_len(length(jsons_vec))) { |
|
|
42 |
curr_module <- names(jsons_vec)[curr_idx] |
|
|
43 |
curr_json <- jsons_vec[[curr_idx]] |
|
|
44 |
for (targ in curr_json[["Targets"]]) { |
|
|
45 |
curr_targ <- targ[["DisplayName"]] |
|
|
46 |
curr_code_class <- gsub("\\d+$", "", targ[["CodeClass"]]) |
|
|
47 |
for (prb in targ[["Probes"]]) { |
|
|
48 |
if (curr_json[["AnalyteType"]] == "Protein") { |
|
|
49 |
curr_RTS_ID <- targ$RTS_ID |
|
|
50 |
} |
|
|
51 |
else { |
|
|
52 |
curr_RTS_ID <- prb$RTS_ID |
|
|
53 |
} |
|
|
54 |
curr_probe_ID <- prb$ProbeID |
|
|
55 |
curr_gene_ID <- paste(prb$GeneID, collapse = ", ") |
|
|
56 |
if (length(prb$GeneID) < 1) { |
|
|
57 |
curr_gene_ID <- NA |
|
|
58 |
} |
|
|
59 |
curr_syst_name <- paste(prb$SystematicName, collapse = ", ") |
|
|
60 |
lookup_df[nrow(lookup_df) + 1, ] <- list(curr_RTS_ID, |
|
|
61 |
curr_targ, curr_module, curr_code_class, curr_probe_ID, |
|
|
62 |
curr_gene_ID, curr_syst_name) |
|
|
63 |
} |
|
|
64 |
} |
|
|
65 |
} |
|
|
66 |
return(lookup_df) |
|
|
67 |
} |
|
|
68 |
|
|
|
69 |
.dccMetadata <- |
|
|
70 |
list(schema = |
|
|
71 |
list("Header" = |
|
|
72 |
data.frame(labelDescription = |
|
|
73 |
c("The version of the file", |
|
|
74 |
"The version of the software used to create the file", |
|
|
75 |
"The date of the sample"), |
|
|
76 |
minVersion = numeric_version(c("0.01", "0.01", "0.01")), |
|
|
77 |
row.names = |
|
|
78 |
c("FileVersion", "SoftwareVersion", "Date"), |
|
|
79 |
stringsAsFactors = FALSE), |
|
|
80 |
"Scan_Attributes" = |
|
|
81 |
data.frame(labelDescription = |
|
|
82 |
c("The sample ID", |
|
|
83 |
"The plate ID", |
|
|
84 |
"The well ID"), |
|
|
85 |
row.names = |
|
|
86 |
c("ID", "Plate_ID", "Well"), |
|
|
87 |
minVersion = numeric_version(c(rep("0.01", 3L))), |
|
|
88 |
stringsAsFactors = FALSE), |
|
|
89 |
"NGS_Processing_Attributes" = |
|
|
90 |
data.frame(labelDescription = |
|
|
91 |
c(NA_character_, |
|
|
92 |
NA_integer_, |
|
|
93 |
NA_integer_, |
|
|
94 |
NA_integer_, |
|
|
95 |
NA_integer_, |
|
|
96 |
NA_real_, |
|
|
97 |
NA_real_), |
|
|
98 |
minVersion = numeric_version(c(rep("0.01", 7L))), |
|
|
99 |
row.names = |
|
|
100 |
c("SeqSetId", "Raw", "Trimmed", |
|
|
101 |
"Stitched", "Aligned", "umiQ30", "rtsQ30"), |
|
|
102 |
stringsAsFactors = FALSE), |
|
|
103 |
"Code_Summary" = |
|
|
104 |
data.frame(labelDescription = |
|
|
105 |
c(NA_character_, NA_integer_), |
|
|
106 |
minVersion = numeric_version(c(rep("0.01", 2L))), |
|
|
107 |
row.names = c("RTS_ID", "Count"), |
|
|
108 |
stringsAsFactors = FALSE) |
|
|
109 |
) |
|
|
110 |
) |
|
|
111 |
|
|
|
112 |
|
|
|
113 |
.dccMetadata[["protocolData"]] <- |
|
|
114 |
do.call(rbind, |
|
|
115 |
unname(head(.dccMetadata[["schema"]], 3L)))[, "labelDescription", |
|
|
116 |
drop = FALSE] |
|
|
117 |
|
|
|
118 |
rownames(.dccMetadata[["protocolData"]])[rownames(.dccMetadata[["protocolData"]]) == "ID"] <- "SampleID" |
|
|
119 |
|
|
|
120 |
|
|
|
121 |
.codeClassMetadata <- |
|
|
122 |
c("CodeClass,IsControl,Analyte", |
|
|
123 |
"Endogenous,FALSE,gx|cnv|fusion", |
|
|
124 |
"Housekeeping,TRUE,gx|fusion", |
|
|
125 |
"Positive,TRUE,general", |
|
|
126 |
"Negative,TRUE,general", |
|
|
127 |
"Binding,TRUE,general", |
|
|
128 |
"Purification,TRUE,general", |
|
|
129 |
"Reserved,TRUE,general", |
|
|
130 |
"SNV_INPUT_CTL,TRUE,SNV", |
|
|
131 |
"SNV_NEG,TRUE,SNV", |
|
|
132 |
"SNV_POS,TRUE,SNV", |
|
|
133 |
"SNV_UDG_CTL,TRUE,SNV", |
|
|
134 |
"SNV_PCR_CTL,TRUE,SNV", |
|
|
135 |
"SNV_REF,FALSE,SNV", |
|
|
136 |
"SNV_VAR,FALSE,SNV", |
|
|
137 |
"PROTEIN,FALSE,protein", |
|
|
138 |
"PROTEIN_NEG,TRUE,protein", |
|
|
139 |
"PROTEIN_CELL_NORM,TRUE,protein", |
|
|
140 |
"Restriction Site,TRUE,CNV", |
|
|
141 |
"Invariant,TRUE,CNV") |
|
|
142 |
.codeClassMetadata <- |
|
|
143 |
utils::read.csv(textConnection(paste0(.codeClassMetadata, collapse = "\n")), |
|
|
144 |
colClasses = c("character", "logical", "character"), |
|
|
145 |
stringsAsFactors = FALSE) |
|
|
146 |
|
|
|
147 |
|
|
|
148 |
.validDccSchema <- |
|
|
149 |
function(x, fileVersion, |
|
|
150 |
section = c("Header", "Scan_Attributes", "NGS_Processing_Attributes", "Code_Summary")) |
|
|
151 |
{ |
|
|
152 |
section <- match.arg(section) |
|
|
153 |
schema <- .dccMetadata[["schema"]][[section]] |
|
|
154 |
expectedNames <- row.names(schema)[schema[,"minVersion"] <= fileVersion] |
|
|
155 |
if (all(expectedNames %in% colnames(x))) { |
|
|
156 |
TRUE |
|
|
157 |
} else { |
|
|
158 |
sprintf("<%s> section must contain %s", section, |
|
|
159 |
paste0("\"", expectedNames, "\"", collapse = ", ")) |
|
|
160 |
} |
|
|
161 |
} |
|
|
162 |
|
|
|
163 |
|
|
|
164 |
.allNA <- function(x) { |
|
|
165 |
all(is.na(x)) |
|
|
166 |
} |
|
|
167 |
|
|
|
168 |
.allTRUE <- function(x) { |
|
|
169 |
is.logical(x) && !anyNA(x) && all(x) |
|
|
170 |
} |
|
|
171 |
|
|
|
172 |
.allFALSE <- function(x) { |
|
|
173 |
is.logical(x) && !anyNA(x) && !any(x) |
|
|
174 |
} |
|
|
175 |
|
|
|
176 |
.allZero <- function(x) { |
|
|
177 |
is.numeric(x) && !anyNA(x) && identical(range(x), c(0, 0)) |
|
|
178 |
} |
|
|
179 |
|
|
|
180 |
.validNonNegativeInteger <- function(x) { |
|
|
181 |
is.integer(x) && !anyNA(x) && min(x) >= 0L |
|
|
182 |
} |
|
|
183 |
|
|
|
184 |
.validNonNegativeNumber <- function(x) { |
|
|
185 |
is.numeric(x) && !anyNA(x) && min(x) >= 0 |
|
|
186 |
} |
|
|
187 |
|
|
|
188 |
.validPositiveNumber <- function(x) { |
|
|
189 |
is.numeric(x) && !anyNA(x) && min(x) > 0 |
|
|
190 |
} |
|
|
191 |
|
|
|
192 |
|
|
|
193 |
#### |
|
|
194 |
# Basilisk Environment #### |
|
|
195 |
#### |
|
|
196 |
|
|
|
197 |
#' get the Python Basilisk environment |
|
|
198 |
#' |
|
|
199 |
#' Defines a conda environment via Basilisk, which is used to convert R objects to Zarr stores. |
|
|
200 |
#' |
|
|
201 |
#' @export |
|
|
202 |
getBasilisk <- function(){ |
|
|
203 |
|
|
|
204 |
if(!requireNamespace('basilisk')) |
|
|
205 |
stop("Please install basilisk package!: BiocManager::install('basilisk')") |
|
|
206 |
|
|
|
207 |
basilisk.packages=c( |
|
|
208 |
"numpy==1.*", |
|
|
209 |
"pandas==1.*", |
|
|
210 |
"anndata==0.8.*", |
|
|
211 |
"h5py==3.*", |
|
|
212 |
"hdf5==1.*", |
|
|
213 |
"natsort==7.*", |
|
|
214 |
"packaging==20.*", |
|
|
215 |
"scipy==1.*", |
|
|
216 |
"sqlite==3.*", |
|
|
217 |
"zarr==2.*", |
|
|
218 |
"numcodecs==0.*", |
|
|
219 |
"tifffile==2024.2.12" |
|
|
220 |
) |
|
|
221 |
basilisk.pip=c( |
|
|
222 |
"ome-zarr==0.2.1" |
|
|
223 |
) |
|
|
224 |
|
|
|
225 |
py_env <- basilisk::BasiliskEnvironment( |
|
|
226 |
envname="VoltRon_basilisk_env", |
|
|
227 |
pkgname="VoltRon", |
|
|
228 |
packages=basilisk.packages, |
|
|
229 |
pip=basilisk.pip |
|
|
230 |
) |
|
|
231 |
|
|
|
232 |
py_env |
|
|
233 |
} |
|
|
234 |
|
|
|
235 |
#### |
|
|
236 |
# Other Auxiliary tools #### |
|
|
237 |
#### |
|
|
238 |
|
|
|
239 |
fill.na <- function(x, i = 5) { |
|
|
240 |
if (is.na(x)[i]) { |
|
|
241 |
return(round(mean(x, na.rm = TRUE), 0)) |
|
|
242 |
} |
|
|
243 |
else { |
|
|
244 |
return(round(x[i], 0)) |
|
|
245 |
} |
|
|
246 |
} |
|
|
247 |
|
|
|
248 |
#' slotApply |
|
|
249 |
#' |
|
|
250 |
#' apply to slots |
|
|
251 |
#' |
|
|
252 |
#' @param x object |
|
|
253 |
#' @param FUN function |
|
|
254 |
#' @param ... arguments passed to \code{FUN} |
|
|
255 |
#' |
|
|
256 |
#' @importFrom methods slot slotNames |
|
|
257 |
#' |
|
|
258 |
slotApply <- function(x,FUN,...){ |
|
|
259 |
cl <- class(x) |
|
|
260 |
result <- list() |
|
|
261 |
for(i in methods::slotNames(cl)){ |
|
|
262 |
result[[i]] <- FUN(methods::slot(x,i),...) |
|
|
263 |
} |
|
|
264 |
result |
|
|
265 |
} |
|
|
266 |
|
|
|
267 |
#' slotToList |
|
|
268 |
#' |
|
|
269 |
#' slot to list |
|
|
270 |
#' |
|
|
271 |
#' @param x object |
|
|
272 |
#' |
|
|
273 |
#' @importFrom methods slot slotNames |
|
|
274 |
#' |
|
|
275 |
slotToList <- function(x){ |
|
|
276 |
returnlist <- list() |
|
|
277 |
namesslot <- methods::slotNames(x) |
|
|
278 |
for(cur_slot in namesslot) |
|
|
279 |
returnlist[[cur_slot]] <- methods::slot(x, name = cur_slot) |
|
|
280 |
returnlist |
|
|
281 |
} |
|
|
282 |
|
|
|
283 |
ggname <- function(prefix, grob) { |
|
|
284 |
grob$name <- grid::grobName(grob, prefix) |
|
|
285 |
grob |
|
|
286 |
} |
|
|
287 |
|
|
|
288 |
quiet <- function(x) { |
|
|
289 |
sink(tempfile()) |
|
|
290 |
on.exit(sink()) |
|
|
291 |
invisible(force(x)) |
|
|
292 |
} |
|
|
293 |
|
|
|
294 |
stopQuietly <- function(...) { |
|
|
295 |
blankMsg <- sprintf("\r%s\r", paste(rep(" ", getOption("width")-1L), collapse=" ")); |
|
|
296 |
stop(simpleError(blankMsg)); |
|
|
297 |
} |
|
|
298 |
|
|
|
299 |
#' make_css |
|
|
300 |
#' |
|
|
301 |
#' make_css from \code{tableHTML} package |
|
|
302 |
#' |
|
|
303 |
#' @param ... css style definitions. Each object you provide must be a list of three elements. The first element will be a vector of the selectors to be styled (e.g. table, th, an id or html class). If the first element is a vector of length greater than one then the selectors will be comma separated in the css. The second element will be a vector of the css definitions and the third element will a vector of the values of those definitions. |
|
|
304 |
#' @param file Character sting. If a file name is provided then the css code will be printed into that file. If the argument is NULL (default) then a string will be returned. |
|
|
305 |
#' |
|
|
306 |
#' @importFrom shiny HTML |
|
|
307 |
#' |
|
|
308 |
#' @noRd |
|
|
309 |
make_css <- function (..., file = NULL) |
|
|
310 |
{ |
|
|
311 |
css_defs <- list(...) |
|
|
312 |
for (x in css_defs) { |
|
|
313 |
if ((!is.list(x)) | (length(x) != 3L)) { |
|
|
314 |
stop("Each element in ... needs to be a list of three elements") |
|
|
315 |
} |
|
|
316 |
if (length(x[[2]]) != length(x[[3]])) { |
|
|
317 |
stop("The second and third elements of each list need to have the same length") |
|
|
318 |
} |
|
|
319 |
} |
|
|
320 |
all_css <- vapply(css_defs, function(x) { |
|
|
321 |
css_comp <- paste0(x[[2]], ": ", x[[3]], ";") |
|
|
322 |
style <- paste(css_comp, collapse = "\n ") |
|
|
323 |
to_be_styled <- paste(x[[1]], collapse = ",\n") |
|
|
324 |
paste0(to_be_styled, " {\n ", style, "\n}\n") |
|
|
325 |
}, FUN.VALUE = character(1)) |
|
|
326 |
css_string <- shiny::HTML(paste(all_css, collapse = "\n")) |
|
|
327 |
if (is.null(file)) { |
|
|
328 |
css_string |
|
|
329 |
} |
|
|
330 |
else { |
|
|
331 |
message(css_string, file = file) |
|
|
332 |
invisible(NULL) |
|
|
333 |
} |
|
|
334 |
} |
|
|
335 |
|
|
|
336 |
#' Fast creation of dummy variables |
|
|
337 |
#' |
|
|
338 |
#' Quickly create dummy (binary) columns from character and |
|
|
339 |
#' factor type columns in the inputted data (and numeric columns if specified.) |
|
|
340 |
#' This function is useful for statistical analysis when you want binary |
|
|
341 |
#' columns rather than character columns. Adapted from the \code{fastDummies} package (https://jacobkap.github.io/fastDummies/) |
|
|
342 |
#' |
|
|
343 |
#' @param .data |
|
|
344 |
#' An object with the data set you want to make dummy columns from. |
|
|
345 |
#' @param select_columns |
|
|
346 |
#' Vector of column names that you want to create dummy variables from. |
|
|
347 |
#' If NULL (default), uses all character and factor columns. |
|
|
348 |
#' @param remove_first_dummy |
|
|
349 |
#' Removes the first dummy of every variable such that only n-1 dummies remain. |
|
|
350 |
#' This avoids multicollinearity issues in models. |
|
|
351 |
#' @param remove_most_frequent_dummy |
|
|
352 |
#' Removes the most frequently observed category such that only n-1 dummies |
|
|
353 |
#' remain. If there is a tie for most frequent, will remove the first |
|
|
354 |
#' (by alphabetical order) category that is tied for most frequent. |
|
|
355 |
#' @param ignore_na |
|
|
356 |
#' If TRUE, ignores any NA values in the column. If FALSE (default), then it |
|
|
357 |
#' will make a dummy column for value_NA and give a 1 in any row which has a |
|
|
358 |
#' NA value. |
|
|
359 |
#' @param split |
|
|
360 |
#' A string to split a column when multiple categories are in the cell. For |
|
|
361 |
#' example, if a variable is Pets and the rows are "cat", "dog", and "turtle", |
|
|
362 |
#' each of these pets would become its own dummy column. If one row is "cat, dog", |
|
|
363 |
#' then a split value of "," this row would have a value of 1 for both the cat |
|
|
364 |
#' and dog dummy columns. |
|
|
365 |
#' @param remove_selected_columns |
|
|
366 |
#' If TRUE (not default), removes the columns used to generate the dummy columns. |
|
|
367 |
#' @param omit_colname_prefix |
|
|
368 |
#' If TRUE (not default) and `length(select_columns) == 1`, omit pre-pending the |
|
|
369 |
#' name of `select_columns` to the names of the newly generated dummy columns |
|
|
370 |
#' |
|
|
371 |
#' @return |
|
|
372 |
#' A data.frame (or tibble or data.table, depending on input data type) with |
|
|
373 |
#' same number of rows as inputted data and original columns plus the newly |
|
|
374 |
#' created dummy columns. |
|
|
375 |
#' |
|
|
376 |
#' @importFrom data.table as.data.table is.data.table chmatch alloc.col set |
|
|
377 |
#' @importFrom stringr str_sort str_order |
|
|
378 |
#' |
|
|
379 |
dummy_cols <- function(.data, select_columns = NULL, remove_first_dummy = FALSE, |
|
|
380 |
remove_most_frequent_dummy = FALSE, ignore_na = FALSE, split = NULL, |
|
|
381 |
remove_selected_columns = FALSE, omit_colname_prefix = FALSE) |
|
|
382 |
{ |
|
|
383 |
stopifnot(is.null(select_columns) || is.character(select_columns), |
|
|
384 |
select_columns != "", is.logical(remove_first_dummy), |
|
|
385 |
length(remove_first_dummy) == 1, is.logical(remove_selected_columns)) |
|
|
386 |
if (remove_first_dummy == TRUE & remove_most_frequent_dummy == |
|
|
387 |
TRUE) { |
|
|
388 |
stop("Select either 'remove_first_dummy' or 'remove_most_frequent_dummy'\n to proceed.") |
|
|
389 |
} |
|
|
390 |
if (is.vector(.data)) { |
|
|
391 |
.data <- data.frame(.data = .data, stringsAsFactors = FALSE) |
|
|
392 |
} |
|
|
393 |
data_type <- check_type(.data) |
|
|
394 |
if (!data.table::is.data.table(.data)) { |
|
|
395 |
.data <- data.table::as.data.table(.data) |
|
|
396 |
} |
|
|
397 |
if (!is.null(select_columns)) { |
|
|
398 |
char_cols <- select_columns |
|
|
399 |
cols_not_in_data <- char_cols[!char_cols %in% names(.data)] |
|
|
400 |
char_cols <- char_cols[!char_cols %in% cols_not_in_data] |
|
|
401 |
if (length(char_cols) == 0) { |
|
|
402 |
stop("select_columns is/are not in data. Please check data and spelling.") |
|
|
403 |
} |
|
|
404 |
} |
|
|
405 |
else if (ncol(.data) == 1) { |
|
|
406 |
char_cols <- names(.data) |
|
|
407 |
} |
|
|
408 |
else { |
|
|
409 |
char_cols <- sapply(.data, class) |
|
|
410 |
char_cols <- char_cols[char_cols %in% c("factor", "character")] |
|
|
411 |
char_cols <- names(char_cols) |
|
|
412 |
} |
|
|
413 |
if (length(char_cols) == 0 && is.null(select_columns)) { |
|
|
414 |
stop("No character or factor columns found. ", |
|
|
415 |
"Please use select_columns to choose columns.") |
|
|
416 |
} |
|
|
417 |
if (!is.null(select_columns) && length(cols_not_in_data) > |
|
|
418 |
0) { |
|
|
419 |
warning("NOTE: The following select_columns input(s) ", |
|
|
420 |
"is not a column in data:\n", names(cols_not_in_data), "\t") |
|
|
421 |
} |
|
|
422 |
for (col_name in char_cols) { |
|
|
423 |
if (is.factor(.data[[col_name]])) { |
|
|
424 |
unique_vals <- levels(.data[[col_name]]) |
|
|
425 |
if (any(is.na(.data[[col_name]]))) { |
|
|
426 |
unique_vals <- c(unique_vals, NA) |
|
|
427 |
} |
|
|
428 |
} |
|
|
429 |
else { |
|
|
430 |
unique_vals <- unique(.data[[col_name]]) |
|
|
431 |
unique_vals <- stringr::str_sort(unique_vals, na_last = TRUE, |
|
|
432 |
locale = "en_US", numeric = TRUE) |
|
|
433 |
} |
|
|
434 |
unique_vals <- as.character(unique_vals) |
|
|
435 |
if (!is.null(split)) { |
|
|
436 |
unique_vals <- unique(trimws(unlist(strsplit(unique_vals, |
|
|
437 |
split = split)))) |
|
|
438 |
} |
|
|
439 |
if (ignore_na) { |
|
|
440 |
unique_vals <- unique_vals[!is.na(unique_vals)] |
|
|
441 |
} |
|
|
442 |
if (remove_most_frequent_dummy) { |
|
|
443 |
vals <- as.character(.data[[col_name]]) |
|
|
444 |
vals <- data.frame(sort(table(vals), decreasing = TRUE), |
|
|
445 |
stringsAsFactors = FALSE) |
|
|
446 |
top_vals <- vals[vals$Freq %in% max(vals$Freq), ] |
|
|
447 |
other_vals <- vals$vals[!vals$Freq %in% max(vals$Freq)] |
|
|
448 |
other_vals <- as.character(other_vals) |
|
|
449 |
top_vals <- top_vals[stringr::str_order(top_vals$vals, |
|
|
450 |
na_last = TRUE, locale = "en_US", numeric = TRUE), |
|
|
451 |
] |
|
|
452 |
if (nrow(top_vals) == 1) { |
|
|
453 |
top_vals <- NULL |
|
|
454 |
} |
|
|
455 |
else { |
|
|
456 |
top_vals <- as.character(top_vals$vals[2:nrow(top_vals)]) |
|
|
457 |
} |
|
|
458 |
unique_vals <- c(top_vals, other_vals) |
|
|
459 |
unique_vals <- stringr::str_sort(unique_vals, na_last = TRUE, |
|
|
460 |
locale = "en_US", numeric = TRUE) |
|
|
461 |
} |
|
|
462 |
if (remove_first_dummy) { |
|
|
463 |
unique_vals <- unique_vals[-1] |
|
|
464 |
} |
|
|
465 |
data.table::alloc.col(.data, ncol(.data) + length(unique_vals)) |
|
|
466 |
.data[, paste0(col_name, "_", unique_vals)] <- 0L |
|
|
467 |
for (unique_value in unique_vals) { |
|
|
468 |
data.table::set(.data, i = which(data.table::chmatch(as.character(.data[[col_name]]), |
|
|
469 |
unique_value, nomatch = 0) == 1L), j = paste0(col_name, |
|
|
470 |
"_", unique_value), value = 1L) |
|
|
471 |
if (!is.na(unique_value)) { |
|
|
472 |
data.table::set(.data, i = which(is.na(.data[[col_name]])), |
|
|
473 |
j = paste0(col_name, "_", unique_value), value = NA) |
|
|
474 |
} |
|
|
475 |
if (!is.null(split)) { |
|
|
476 |
max_split_length <- max(sapply(strsplit(as.character(.data[[col_name]]), |
|
|
477 |
split = split), length)) |
|
|
478 |
for (split_length in seq_len(max_split_length)) { |
|
|
479 |
data.table::set(.data, i = which(data.table::chmatch(as.character(trimws(sapply(strsplit(as.character(.data[[col_name]]), |
|
|
480 |
split = split), `[`, split_length))), unique_value, |
|
|
481 |
nomatch = 0) == 1L), j = paste0(col_name, |
|
|
482 |
"_", unique_value), value = 1L) |
|
|
483 |
} |
|
|
484 |
if (is.na(unique_value)) { |
|
|
485 |
.data[[paste0(col_name, "_", unique_value)]][which(!is.na(.data[[col_name]]))] <- 0 |
|
|
486 |
} |
|
|
487 |
} |
|
|
488 |
} |
|
|
489 |
} |
|
|
490 |
if (remove_selected_columns) { |
|
|
491 |
.data <- .data[-which(names(.data) %in% char_cols)] |
|
|
492 |
} |
|
|
493 |
.data <- fix_data_type(.data, data_type) |
|
|
494 |
if (omit_colname_prefix) { |
|
|
495 |
if (length(select_columns) == 1) { |
|
|
496 |
new_col_index <- as.logical(rowSums(sapply(unique_vals, |
|
|
497 |
function(x) grepl(paste0(select_columns, "_", |
|
|
498 |
x), names(.data))))) |
|
|
499 |
names(.data)[new_col_index] <- gsub(paste0(select_columns, |
|
|
500 |
"_"), "", names(.data)[new_col_index]) |
|
|
501 |
} |
|
|
502 |
else { |
|
|
503 |
message("Can't omit the colname prefix when recoding more than one column.") |
|
|
504 |
message("Returning prefixed dummy columns.") |
|
|
505 |
} |
|
|
506 |
} |
|
|
507 |
return(.data) |
|
|
508 |
} |
|
|
509 |
|
|
|
510 |
#' @importFrom data.table is.data.table |
|
|
511 |
#' @noRd |
|
|
512 |
check_type <- function(.data) { |
|
|
513 |
if (data.table::is.data.table(.data)) { |
|
|
514 |
data_type <- "is_data_table" |
|
|
515 |
} else if (inherits(.data, "tbl_df")) { |
|
|
516 |
data_type <- "is_tibble" |
|
|
517 |
} else { |
|
|
518 |
data_type <- "is_data_frame" |
|
|
519 |
} |
|
|
520 |
|
|
|
521 |
return(data_type) |
|
|
522 |
} |
|
|
523 |
|
|
|
524 |
#' @importFrom dplyr as_tibble |
|
|
525 |
#' @noRd |
|
|
526 |
fix_data_type <- function(.data, data_type) { |
|
|
527 |
if (data_type == "is_data_frame") { |
|
|
528 |
.data <- as.data.frame(.data, stringsAsFactors = FALSE) |
|
|
529 |
} else if (data_type == "is_tibble") { |
|
|
530 |
.data <- dplyr::as_tibble(.data) |
|
|
531 |
} |
|
|
532 |
|
|
|
533 |
return(.data) |
|
|
534 |
} |
|
|
535 |
|
|
|
536 |
#' CSS string helper |
|
|
537 |
#' |
|
|
538 |
#' Convenience function for building CSS style declarations (i.e. the string |
|
|
539 |
#' that goes into a style attribute, or the parts that go inside curly braces in |
|
|
540 |
#' a full stylesheet). |
|
|
541 |
#' |
|
|
542 |
#' CSS uses `'-'` (minus) as a separator character in property names, but |
|
|
543 |
#' this is an inconvenient character to use in an R function argument name. |
|
|
544 |
#' Instead, you can use `'.'` (period) and/or `'_'` (underscore) as |
|
|
545 |
#' separator characters. For example, `css(font.size = "12px")` yields |
|
|
546 |
#' `"font-size:12px;"`. |
|
|
547 |
#' |
|
|
548 |
#' To mark a property as `!important`, add a `'!'` character to the end |
|
|
549 |
#' of the property name. (Since `'!'` is not normally a character that can be |
|
|
550 |
#' used in an identifier in R, you'll need to put the name in double quotes or |
|
|
551 |
#' backticks.) |
|
|
552 |
#' |
|
|
553 |
#' Argument values will be converted to strings using |
|
|
554 |
#' `paste(collapse = " ")`. Any property with a value of `NULL` or |
|
|
555 |
#' `""` (after paste) will be dropped. |
|
|
556 |
#' |
|
|
557 |
#' @param ... Named style properties, where the name is the property name and |
|
|
558 |
#' the argument is the property value. See Details for conversion rules. |
|
|
559 |
#' @param collapse_ (Note that the parameter name has a trailing underscore |
|
|
560 |
#' character.) Character to use to collapse properties into a single string; |
|
|
561 |
#' likely `""` (the default) for style attributes, and either `"\n"` |
|
|
562 |
#' or `NULL` for style blocks. |
|
|
563 |
#' |
|
|
564 |
#' @importFrom rlang dots_list |
|
|
565 |
#' |
|
|
566 |
#' @noRd |
|
|
567 |
css <- function(..., collapse_ = "") { |
|
|
568 |
props <- rlang::dots_list(...) |
|
|
569 |
if (length(props) == 0) { |
|
|
570 |
return(NULL) |
|
|
571 |
} |
|
|
572 |
|
|
|
573 |
if (is.null(names(props)) || any(names(props) == "")) { |
|
|
574 |
stop("cssList expects all arguments to be named") |
|
|
575 |
} |
|
|
576 |
|
|
|
577 |
# Necessary to make factors show up as level names, not numbers |
|
|
578 |
props[] <- lapply(props, paste, collapse = " ") |
|
|
579 |
|
|
|
580 |
# Drop null args |
|
|
581 |
props <- props[!sapply(props, empty)] |
|
|
582 |
if (length(props) == 0) { |
|
|
583 |
return(NULL) |
|
|
584 |
} |
|
|
585 |
|
|
|
586 |
# Translate camelCase, snake_case, and dot.case to kebab-case |
|
|
587 |
# For standard CSS properties only, not CSS variables |
|
|
588 |
is_css_var <- grepl("^--", names(props)) |
|
|
589 |
names(props)[!is_css_var] <- standardize_property_names(names(props)[!is_css_var]) |
|
|
590 |
|
|
|
591 |
# Create "!important" suffix for each property whose name ends with !, then |
|
|
592 |
# remove the ! from the property name |
|
|
593 |
important <- ifelse(grepl("!$", names(props), perl = TRUE), " !important", "") |
|
|
594 |
names(props) <- sub("!$", "", names(props), perl = TRUE) |
|
|
595 |
|
|
|
596 |
paste0(names(props), ":", props, important, ";", collapse = collapse_) |
|
|
597 |
} |
|
|
598 |
|
|
|
599 |
empty <- function(x) { |
|
|
600 |
length(x) == 0 || (is.character(x) && !any(nzchar(x))) |
|
|
601 |
} |
|
|
602 |
|
|
|
603 |
standardize_property_names <- function(x) { |
|
|
604 |
# camelCase to kebab-case |
|
|
605 |
x <- gsub("([A-Z])", "-\\1", x) |
|
|
606 |
x <- tolower(x) |
|
|
607 |
# snake_case and dot.case to kebab-case |
|
|
608 |
gsub("[._]", "-", x) |
|
|
609 |
} |
|
|
610 |
|
|
|
611 |
#' @importFrom grDevices hcl |
|
|
612 |
hue_pal <- function(n, h = c(0, 360) + 15, c = 100, l = 65, h.start = 0, direction = 1) |
|
|
613 |
{ |
|
|
614 |
if (n == 0) { |
|
|
615 |
stop("Must request at least one colour from a hue palette.") |
|
|
616 |
} |
|
|
617 |
if ((diff(h)%%360) < 1) { |
|
|
618 |
h[2] <- h[2] - 360/n |
|
|
619 |
} |
|
|
620 |
hues <- seq(h[1], h[2], length.out = n) |
|
|
621 |
hues <- (hues + h.start)%%360 |
|
|
622 |
hcl <- cbind(hues, c, l) |
|
|
623 |
pal <- apply(hcl, 1, function(x){ |
|
|
624 |
grDevices::hcl(x[1], x[2], x[3]) |
|
|
625 |
}) |
|
|
626 |
if (direction == -1) { |
|
|
627 |
rev(pal) |
|
|
628 |
} |
|
|
629 |
else { |
|
|
630 |
pal |
|
|
631 |
} |
|
|
632 |
} |
|
|
633 |
|
|
|
634 |
rescale_numeric <- function(x, to = c(0, 1), from = range(x, na.rm = TRUE, finite = TRUE), ...) { |
|
|
635 |
(x - from[1]) / diff(from) * diff(to) + to[1] |
|
|
636 |
} |
|
|
637 |
|
|
|
638 |
as.raster_array <- function (x, max = 1, ...) |
|
|
639 |
{ |
|
|
640 |
if (!is.numeric(x)) { |
|
|
641 |
if (is.raw(x)) { |
|
|
642 |
storage.mode(x) <- "integer" |
|
|
643 |
max <- 255L |
|
|
644 |
} |
|
|
645 |
else stop("a raster array must be numeric") |
|
|
646 |
} |
|
|
647 |
if (length(d <- dim(x)) != 3L) |
|
|
648 |
stop("a raster array must have exactly 3 dimensions") |
|
|
649 |
r <- array(if (d[3L] == 3L) |
|
|
650 |
rgb(t(x[, , 1L]), t(x[, , 2L]), t(x[, , 3L]), maxColorValue = max) |
|
|
651 |
else if (d[3L] == 4L) |
|
|
652 |
rgb(t(x[, , 1L]), t(x[, , 2L]), t(x[, , 3L]), t(x[, , 4L]), maxColorValue = max) |
|
|
653 |
else if (d[3L] == 1L) |
|
|
654 |
rgb(t(x[, , 1L]), t(x[, , 1L]), t(x[, , 1L]), maxColorValue = max) |
|
|
655 |
else stop("a raster array must have exactly 1, 3 or 4 planes"), |
|
|
656 |
dim = d[seq_len(2)]) |
|
|
657 |
class(r) <- "raster" |
|
|
658 |
r |
|
|
659 |
} |
|
|
660 |
|
|
|
661 |
avgHexColor <- function(colors){ |
|
|
662 |
rgb(t(Reduce(`+`, lapply(colors, col2rgb))/3), maxColorValue=255) |
|
|
663 |
} |
|
|
664 |
|
|
|
665 |
#### |
|
|
666 |
## ggedit tools #### |
|
|
667 |
## See https://github.com/yonicd/ggedit/tree/master/R |
|
|
668 |
#### |
|
|
669 |
|
|
|
670 |
#' @title ggplot2 layer proto extraction |
|
|
671 |
#' @description Extract geom, stat and position protos from a ggplot2 layer |
|
|
672 |
#' @param l ggproto |
|
|
673 |
#' @noRd |
|
|
674 |
proto_features <- function(l) { |
|
|
675 |
a <- sapply(c("position", "geom", "stat"), function(x) { |
|
|
676 |
class(l[[x]])[1] |
|
|
677 |
}) |
|
|
678 |
|
|
|
679 |
data.frame(t(a), stringsAsFactors = FALSE) |
|
|
680 |
} |
|
|
681 |
|
|
|
682 |
# forked from https://github.com/yihui/knitr/blob/master/R/defaults.R |
|
|
683 |
#' @importFrom stats setNames |
|
|
684 |
#' @noRd |
|
|
685 |
new_defaults <- function(value = list()) { |
|
|
686 |
defaults <- value |
|
|
687 |
|
|
|
688 |
get <- function(name, default = FALSE, drop = TRUE, regex=FALSE, ...) { |
|
|
689 |
if (default) defaults <- value # this is only a local version |
|
|
690 |
if (missing(name)) { |
|
|
691 |
defaults |
|
|
692 |
} else { |
|
|
693 |
if (drop && length(name) == 1) { |
|
|
694 |
if (regex) { |
|
|
695 |
name_grep <- grep(name, names(defaults), value = TRUE, ...) |
|
|
696 |
stats::setNames(defaults[name_grep], name_grep) |
|
|
697 |
} else { |
|
|
698 |
defaults[[name]] |
|
|
699 |
} |
|
|
700 |
} else { |
|
|
701 |
stats::setNames(defaults[name], name) |
|
|
702 |
} |
|
|
703 |
} |
|
|
704 |
} |
|
|
705 |
|
|
|
706 |
set <- function(...) { |
|
|
707 |
dots <- list(...) |
|
|
708 |
if (length(dots) == 0) return() |
|
|
709 |
if (is.null(names(dots)) && length(dots) == 1 && is.list(dots[[1]])) { |
|
|
710 |
if (length(dots <- dots[[1]]) == 0) { |
|
|
711 |
return() |
|
|
712 |
} |
|
|
713 |
} |
|
|
714 |
defaults <<- merge(dots) |
|
|
715 |
invisible(NULL) |
|
|
716 |
} |
|
|
717 |
|
|
|
718 |
# merge <- function(values) merge_list(defaults, values) |
|
|
719 |
|
|
|
720 |
restore <- function(target = value) defaults <<- target |
|
|
721 |
|
|
|
722 |
append <- function(...) { |
|
|
723 |
dots <- list(...) |
|
|
724 |
if (length(dots) == 0) return() |
|
|
725 |
if (is.null(names(dots)) && length(dots) == 1 && is.list(dots[[1]])) { |
|
|
726 |
if (length(dots <- dots[[1]]) == 0) { |
|
|
727 |
return() |
|
|
728 |
} |
|
|
729 |
} |
|
|
730 |
dots <- sapply(names(dots), function(x) dots[[x]] <- c(defaults[[x]], dots[[x]]), simplify = FALSE) |
|
|
731 |
defaults <<- merge(dots) |
|
|
732 |
invisible(NULL) |
|
|
733 |
} |
|
|
734 |
|
|
|
735 |
list(get = get, set = set, append = append, merge = merge, restore = restore) |
|
|
736 |
} |
|
|
737 |
|
|
|
738 |
#' @title Creates an independent copy of a ggplot layer object |
|
|
739 |
#' @description Creates copies of ggplot layers from within ggplot objects that |
|
|
740 |
#' are independent of the parent object. |
|
|
741 |
#' @details ggplot objects are comprimsed of layer objects. Once compiled they |
|
|
742 |
#' are part of the plot object environment and if they are changed internally |
|
|
743 |
#' regardless of where they are in the (ie different environment) it will change |
|
|
744 |
#' the original plot. This function allows to create replicates of the plot layers |
|
|
745 |
#' and edit them independent of the original plot. When setting verbose to TRUE |
|
|
746 |
#' function returns the ggplot2 call as a string to paste in regular ggplot script |
|
|
747 |
#' to generate the layer. |
|
|
748 |
#' @param l ggplot2 object layer |
|
|
749 |
#' @param verbose toggle to control if the output is ggproto object (verbose==FALSE,default) or string of layer call (verbose==TRUE) |
|
|
750 |
#' @param showDefaults toggle to control if the verbose output shows all the input arguments passed to the proto object (if verbose==FALSE then ignored) |
|
|
751 |
#' @return ggproto or string object (conditional on verbose) |
|
|
752 |
#' |
|
|
753 |
#' @importFrom utils capture.output |
|
|
754 |
#' @importFrom rlang sym '!!' |
|
|
755 |
#' @noRd |
|
|
756 |
cloneLayer <- function (l, verbose = FALSE, showDefaults = TRUE) |
|
|
757 |
{ |
|
|
758 |
geom_opts <- ggedit_opts$get("session_geoms") |
|
|
759 |
parent.layer <- dplyr::left_join(proto_features(l), dplyr::filter(geom_opts, |
|
|
760 |
!grepl("^stat", !!rlang::sym("fn"))), by = c("position", |
|
|
761 |
"geom", "stat")) |
|
|
762 |
if (is.na(parent.layer$fn)) |
|
|
763 |
parent.layer$fn <- paste0(tolower(strsplit(parent.layer$stat, |
|
|
764 |
"(?<=Stat)", perl = TRUE)[[1]]), collapse = "_") |
|
|
765 |
layer.names <- c("mapping", "data", "geom", "position", "stat", |
|
|
766 |
"show.legend", "inherit.aes", "aes_params", "geom_params", |
|
|
767 |
"stat_params") |
|
|
768 |
x <- sapply(layer.names, function(y) { |
|
|
769 |
b <- l[[y]] |
|
|
770 |
if ("waiver" %in% class(b)) |
|
|
771 |
b <- NULL |
|
|
772 |
if (y == "geom") |
|
|
773 |
b <- eval(parse(text = parent.layer$geom)) |
|
|
774 |
if (y == "position") |
|
|
775 |
b <- gsub(y, "", tolower(class(b)[1])) |
|
|
776 |
if (y == "stat") |
|
|
777 |
b <- eval(parse(text = parent.layer$stat)) |
|
|
778 |
b |
|
|
779 |
}) |
|
|
780 |
x$params <- append(x$stat_params, x$geom_params) |
|
|
781 |
x$params <- append(x$params, x$aes_params) |
|
|
782 |
x$params <- x$params[!duplicated(names(x$params))] |
|
|
783 |
x$geom_params <- x$aes_params <- x$stat_params <- NULL |
|
|
784 |
if (verbose) { |
|
|
785 |
nm <- names(x) |
|
|
786 |
nm <- nm[!sapply(x, typeof) %in% c("environment", "closure", |
|
|
787 |
"list")] |
|
|
788 |
geom_aes <- list(geom = parent.layer$fn, mapping = sapply(names(x$mapping), |
|
|
789 |
build_map, y = x$mapping), params = sapply(names(x$params), |
|
|
790 |
build_map, y = x$params), layer = sapply(rev(nm), |
|
|
791 |
build_map, y = x[rev(nm)]), data = paste0("data = ", |
|
|
792 |
paste0(capture.output(dput(x$data)), collapse = "\n"))) |
|
|
793 |
strRet <- sprintf("%s(mapping=aes(%s),%s,%s)", paste0(geom_aes$geom, |
|
|
794 |
collapse = ","), paste0(geom_aes$mapping, collapse = ","), |
|
|
795 |
paste0(geom_aes$params, collapse = ","), paste0(geom_aes$layer, |
|
|
796 |
collapse = ",")) |
|
|
797 |
if (!showDefaults) { |
|
|
798 |
geom_proto <- cloneProto(eval(parse(text = paste0(geom_aes$geom, |
|
|
799 |
"()")))) |
|
|
800 |
geom_diff <- sapply(names(geom_aes)[-1], function(x) geom_aes[[x]][!geom_aes[[x]] %in% |
|
|
801 |
geom_proto[[x]]]) |
|
|
802 |
strRet <- sprintf("%s(aes(%s),%s,%s,%s)", paste0(geom_aes$geom, |
|
|
803 |
collapse = ","), paste0(geom_diff$mapping, collapse = ","), |
|
|
804 |
paste0(geom_diff$params, collapse = ","), paste0(geom_diff$layer, |
|
|
805 |
collapse = ","), geom_aes$data) |
|
|
806 |
} |
|
|
807 |
strRet <- gsub("aes()", "", strRet, fixed = T) |
|
|
808 |
strRet <- gsub("[,]{2,}", ",", strRet) |
|
|
809 |
strRet <- gsub("data=NULL", "", strRet) |
|
|
810 |
strRet <- gsub(",)", ")", strRet) |
|
|
811 |
strRet <- gsub("\\(,", "(", strRet) |
|
|
812 |
strRet |
|
|
813 |
} |
|
|
814 |
else { |
|
|
815 |
do.call(layer, x) |
|
|
816 |
} |
|
|
817 |
} |
|
|
818 |
|
|
|
819 |
#' @importFrom dplyr filter left_join |
|
|
820 |
#' @importFrom rlang sym '!!' |
|
|
821 |
#' @noRd |
|
|
822 |
cloneProto <- function(l) { |
|
|
823 |
|
|
|
824 |
geom_opts <- ggedit_opts$get("session_geoms") |
|
|
825 |
|
|
|
826 |
parent.layer <- proto_features(l) |> |
|
|
827 |
dplyr::left_join( |
|
|
828 |
geom_opts |> dplyr::filter(!grepl("^stat", !!rlang::sym('fn'))), |
|
|
829 |
by = c("position", "geom", "stat") |
|
|
830 |
) |
|
|
831 |
|
|
|
832 |
if (is.na(parent.layer$fn)) { |
|
|
833 |
parent.layer$fn <- paste0(tolower(strsplit(parent.layer$stat, "(?<=Stat)", perl = TRUE)[[1]]), collapse = "_") |
|
|
834 |
} |
|
|
835 |
|
|
|
836 |
layer.names <- c("mapping", "data", "geom", "position", "stat", "show.legend", "inherit.aes", "aes_params", "geom_params", "stat_params") |
|
|
837 |
|
|
|
838 |
x <- sapply(layer.names, function(y) { |
|
|
839 |
b <- l[[y]] |
|
|
840 |
|
|
|
841 |
if ("waiver" %in% class(b)) { |
|
|
842 |
b = NULL |
|
|
843 |
} |
|
|
844 |
|
|
|
845 |
if (y == "geom") { |
|
|
846 |
b <- eval(parse(text = parent.layer$geom)) |
|
|
847 |
} |
|
|
848 |
|
|
|
849 |
if (y == "position") { |
|
|
850 |
b <- gsub(y, "", tolower(class(b)[1])) |
|
|
851 |
} |
|
|
852 |
|
|
|
853 |
if (y == "stat") { |
|
|
854 |
b <- eval(parse(text = parent.layer$stat)) |
|
|
855 |
} |
|
|
856 |
|
|
|
857 |
b |
|
|
858 |
}) |
|
|
859 |
|
|
|
860 |
x$params <- append(x$stat_params, x$geom_params) |
|
|
861 |
x$params <- append(x$params, x$aes_params) |
|
|
862 |
x$params <- x$params[!duplicated(names(x$params))] |
|
|
863 |
|
|
|
864 |
x$geom_params <- x$aes_params <- x$stat_params <- NULL |
|
|
865 |
|
|
|
866 |
fn <- parent.layer$fn |
|
|
867 |
|
|
|
868 |
g <- paste0(fn, "()") |
|
|
869 |
g <- eval(parse(text = g)) |
|
|
870 |
nm <- names(x) |
|
|
871 |
|
|
|
872 |
nm <- nm[!sapply(x, typeof) %in% c("environment", "closure", "list")] |
|
|
873 |
|
|
|
874 |
geom_aes <- list( |
|
|
875 |
geom = fn, |
|
|
876 |
mapping = sapply(names(x$mapping), build_map,y = x$mapping), |
|
|
877 |
params = sapply(names(x$params), build_map, y = x$params), |
|
|
878 |
layer = sapply(rev(nm), build_map, y = x[rev(nm)]) |
|
|
879 |
) |
|
|
880 |
|
|
|
881 |
nDF <- cbind(names(g$geom$default_aes), paste(g$geom$default_aes)) |
|
|
882 |
nDF[grep("colour|fill|color", nDF[, 1]), 2] <- paste0("'", col2hcl(nDF[grep("colour|fill|color", nDF[, 1]), 2], alpha = NULL), "'") |
|
|
883 |
|
|
|
884 |
geom_aes$default <- paste0(apply(nDF, 1, function(x) paste0(x, collapse = "="))) |
|
|
885 |
|
|
|
886 |
geom_aes |
|
|
887 |
} |
|
|
888 |
|
|
|
889 |
#' @title Default and current ggedit options |
|
|
890 |
#' |
|
|
891 |
#' @description Options for functions in the ggedit package. When running R code, the object \code{ggedit_opts} |
|
|
892 |
#' (default options) is not modified by chunk headers (local chunk options are |
|
|
893 |
#' merged with default options), whereas \code{ggedit_opts_current} (current options) |
|
|
894 |
#' changes with different chunk headers and it always reflects the options for |
|
|
895 |
#' the current chunk. |
|
|
896 |
#' |
|
|
897 |
#' Normally we set up the global options once in the first code chunk in a |
|
|
898 |
#' document using \code{ggedit_opts$set()}, so that all \emph{latter} chunks will |
|
|
899 |
#' use these options. Note the global options set in one chunk will not affect |
|
|
900 |
#' the options in this chunk itself, and that is why we often need to set global |
|
|
901 |
#' options in a separate chunk. |
|
|
902 |
#' |
|
|
903 |
#' @note \code{ggedit_opts_current} is read-only in the sense that it does nothing if |
|
|
904 |
#' you call \code{ggedit_opts_current$set()}; you can only query the options via |
|
|
905 |
#' \code{ggedit_opts_current$get()}. |
|
|
906 |
#' @rdname ggeditOpts |
|
|
907 |
#' @noRd |
|
|
908 |
ggedit_opts <- new_defaults(list( |
|
|
909 |
fontDefaults = c( |
|
|
910 |
"sans", |
|
|
911 |
"Canonical", |
|
|
912 |
"mono", |
|
|
913 |
"Courier", |
|
|
914 |
"Helvetica", |
|
|
915 |
"serif", |
|
|
916 |
"Times", |
|
|
917 |
"AvantGarde", |
|
|
918 |
"Bookman", |
|
|
919 |
"Helvetica-Narrow", |
|
|
920 |
"NewCenturySchoolbook", |
|
|
921 |
"Palatino", |
|
|
922 |
"URWGothic", |
|
|
923 |
"URWBookman", |
|
|
924 |
"NimbusMon", |
|
|
925 |
"URWHelvetica", |
|
|
926 |
"NimbusSan", |
|
|
927 |
"NimbusSanCond", |
|
|
928 |
"CenturySch", |
|
|
929 |
"URWPalladio", |
|
|
930 |
"URWTimes", |
|
|
931 |
"NimbusRom" |
|
|
932 |
), |
|
|
933 |
slideDefaults = list( |
|
|
934 |
alpha = c(min = 0, max = 1), |
|
|
935 |
size = c(min = 0, max = 10), |
|
|
936 |
shape = c(min = 1, max = 25), |
|
|
937 |
stroke = c(min = 0, max = 10), |
|
|
938 |
weight = c(min = 0, max = 10), |
|
|
939 |
linetype = c(min = 1, max = 5), |
|
|
940 |
width = c(min = 0, max = 1), |
|
|
941 |
angle = c(min = 0, max = 360), |
|
|
942 |
hjust = c(min = -10, max = 10), |
|
|
943 |
vjust = c(min = -10, max = 10), |
|
|
944 |
stroke = c(min = 0, max = 10), |
|
|
945 |
lineheight = c(min = 0, max = 10), |
|
|
946 |
linewidth = c(min = 0, max = 5), |
|
|
947 |
fontface = c(min = 1, max = 4), |
|
|
948 |
rel_min_height = c(min = 0, max = 1), |
|
|
949 |
scale = c(min = 0, max = 100) |
|
|
950 |
), |
|
|
951 |
themeTips = list( |
|
|
952 |
element_rect = list( |
|
|
953 |
fill = "fill colour", |
|
|
954 |
colour = "border colour", |
|
|
955 |
size = "border size (in pts)", |
|
|
956 |
linetype = paste0( |
|
|
957 |
paste( |
|
|
958 |
seq(0, 6), |
|
|
959 |
c( |
|
|
960 |
"blank", "solid", "dashed", "dotted", "dotdash", |
|
|
961 |
"longdash", "twodash" |
|
|
962 |
), sep = ": " |
|
|
963 |
), |
|
|
964 |
collapse = ", " |
|
|
965 |
) |
|
|
966 |
), |
|
|
967 |
element_line = list( |
|
|
968 |
colour = "line colour", |
|
|
969 |
size = "numeric (in pts) or \n relative to global size rel(numeric)", |
|
|
970 |
linetype = paste0( |
|
|
971 |
paste( |
|
|
972 |
seq(0, 6), |
|
|
973 |
c( |
|
|
974 |
"blank", "solid", "dashed", "dotted", "dotdash", |
|
|
975 |
"longdash", "twodash" |
|
|
976 |
), sep = ": " |
|
|
977 |
), |
|
|
978 |
collapse = ", " |
|
|
979 |
), |
|
|
980 |
lineend = c("butt(default),round,square") |
|
|
981 |
), |
|
|
982 |
element_text = list( |
|
|
983 |
family = shiny::HTML('<a href="http://www.cookbook-r.com/Graphs/Fonts/" target="_blank">font family</a>'), |
|
|
984 |
face = 'font face ("plain", "italic", "bold", "bold.italic")', |
|
|
985 |
colour = "text colour", |
|
|
986 |
size = "text size (in pts)", |
|
|
987 |
hjust = "horizontal justification (in [0, 1])", |
|
|
988 |
vjust = "vertical justification (in [0, 1])", |
|
|
989 |
angle = "angle (in [0, 360])", |
|
|
990 |
lineheight = "numeric line height" |
|
|
991 |
), |
|
|
992 |
justification = list(justification = 'anchor point for positioning legend inside plot <br/> "center" or two-element numeric vector'), |
|
|
993 |
position = list(position = 'the position of legends. <br/> "left", "right", "bottom", "top", or two-element numeric vector') |
|
|
994 |
), |
|
|
995 |
|
|
|
996 |
ThemeDefaultClass = |
|
|
997 |
data.frame( |
|
|
998 |
item = c("angle", "background", "caption", "colour", "face", "family", "fill", "grid.major", "grid.minor", "hjust", "justification", "key", "key.size", "line", "lineheight", "linetype", "margin", "ontop", "position", "size", "subtitle", "switch.pad.grid", "switch.pad.wrap", "text", "text.x", "text.y", "ticks", "ticks.length", "title", "title.x", "title.y", "vjust", "placement"), |
|
|
999 |
class = c("numeric", "character", "character", "character", "character", "character", "character", "character", "character", "numeric", "character", "character", "character", "character", "numeric", "numeric", "numeric", "character", "character", "numeric", "character", "character", "character", "character", "character", "character", "numeric", "numeric", "character", "character", "character", "numeric", "character"), stringsAsFactors = FALSE |
|
|
1000 |
), |
|
|
1001 |
session_geoms = |
|
|
1002 |
data.frame( |
|
|
1003 |
fn = c("annotation_custom", "annotation_logticks", |
|
|
1004 |
"annotation_map", "annotation_raster", "geom_abline", "geom_area", |
|
|
1005 |
"geom_bar", "geom_bin2d", "geom_blank", "geom_boxplot", "geom_col", |
|
|
1006 |
"geom_contour", "geom_count", "geom_crossbar", "geom_curve", |
|
|
1007 |
"geom_density", "geom_density_2d", "geom_density2d", "geom_dotplot", |
|
|
1008 |
"geom_errorbar", "geom_errorbarh", "geom_freqpoly", "geom_hex", |
|
|
1009 |
"geom_histogram", "geom_hline", "geom_jitter", "geom_label", |
|
|
1010 |
"geom_line", "geom_linerange", "geom_map", "geom_path", "geom_point", |
|
|
1011 |
"geom_pointrange", "geom_polygon", "geom_qq", "geom_qq_line", |
|
|
1012 |
"geom_quantile", "geom_raster", "geom_rect", "geom_ribbon", "geom_rug", |
|
|
1013 |
"geom_segment", "geom_sf", "geom_smooth", "geom_spoke", "geom_step", |
|
|
1014 |
"geom_text", "geom_tile", "geom_violin", "geom_vline", "stat_bin", |
|
|
1015 |
"stat_bin_2d", "stat_bin_hex", "stat_bin2d", "stat_binhex", "stat_boxplot", |
|
|
1016 |
"stat_contour", "stat_count", "stat_density", "stat_density_2d", |
|
|
1017 |
"stat_density2d", "stat_ecdf", "stat_ellipse", "stat_function", |
|
|
1018 |
"stat_identity", "stat_qq", "stat_qq_line", "stat_quantile", |
|
|
1019 |
"stat_sf", "stat_smooth", "stat_sum", "stat_summary", "stat_summary_2d", |
|
|
1020 |
"stat_summary_bin", "stat_summary_hex", "stat_unique", "stat_ydensity"), |
|
|
1021 |
geom = c("GeomCustomAnn", "GeomLogticks", "GeomAnnotationMap", |
|
|
1022 |
"GeomRasterAnn", "GeomAbline", "GeomArea", "GeomBar", "GeomTile", |
|
|
1023 |
"GeomBlank", "GeomBoxplot", "GeomCol", "GeomContour", "GeomPoint", |
|
|
1024 |
"GeomCrossbar", "GeomCurve", "GeomDensity", "GeomDensity2d", |
|
|
1025 |
"GeomDensity2d", "GeomDotplot", "GeomErrorbar", "GeomErrorbarh", |
|
|
1026 |
"GeomPath", "GeomHex", "GeomBar", "GeomHline", "GeomPoint", "GeomLabel", |
|
|
1027 |
"GeomLine", "GeomLinerange", "GeomMap", "GeomPath", "GeomPoint", |
|
|
1028 |
"GeomPointrange", "GeomPolygon", "GeomPoint", "GeomPath", "GeomQuantile", |
|
|
1029 |
"GeomRaster", "GeomRect", "GeomRibbon", "GeomRug", "GeomSegment", |
|
|
1030 |
"GeomSf", "GeomSmooth", "GeomSpoke", "GeomStep", "GeomText", |
|
|
1031 |
"GeomTile", "GeomViolin", "GeomVline", "GeomBar", "GeomTile", |
|
|
1032 |
"GeomHex", "GeomTile", "GeomHex", "GeomBoxplot", "GeomContour", |
|
|
1033 |
"GeomBar", "GeomArea", "GeomDensity2d", "GeomDensity2d", "GeomStep", |
|
|
1034 |
"GeomPath", "GeomPath", "GeomPoint", "GeomPoint", "GeomPath", |
|
|
1035 |
"GeomQuantile", "GeomRect", "GeomSmooth", "GeomPoint", "GeomPointrange", |
|
|
1036 |
"GeomTile", "GeomPointrange", "GeomHex", "GeomPoint", "GeomViolin"), |
|
|
1037 |
position = c("PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1038 |
"PositionIdentity", "PositionIdentity", "PositionStack", "PositionStack", |
|
|
1039 |
"PositionIdentity", "PositionIdentity", "PositionDodge2", "PositionStack", |
|
|
1040 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1041 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1042 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1043 |
"PositionStack", "PositionIdentity", "PositionJitter", "PositionIdentity", |
|
|
1044 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1045 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1046 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1047 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1048 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1049 |
"PositionIdentity", "PositionDodge", "PositionIdentity", "PositionStack", |
|
|
1050 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1051 |
"PositionDodge2", "PositionIdentity", "PositionStack", "PositionStack", |
|
|
1052 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1053 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1054 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1055 |
"PositionIdentity", "PositionIdentity", "PositionIdentity", "PositionIdentity", |
|
|
1056 |
"PositionIdentity", "PositionDodge"), |
|
|
1057 |
stat = c("StatIdentity", "StatIdentity", "StatIdentity", "StatIdentity", "StatIdentity", |
|
|
1058 |
"StatIdentity", "StatCount", "StatBin2d", "StatIdentity", "StatBoxplot", |
|
|
1059 |
"StatIdentity", "StatContour", "StatSum", "StatIdentity", "StatIdentity", |
|
|
1060 |
"StatDensity", "StatDensity2d", "StatDensity2d", "StatBindot", |
|
|
1061 |
"StatIdentity", "StatIdentity", "StatBin", "StatBinhex", "StatBin", |
|
|
1062 |
"StatIdentity", "StatIdentity", "StatIdentity", "StatIdentity", |
|
|
1063 |
"StatIdentity", "StatIdentity", "StatIdentity", "StatIdentity", |
|
|
1064 |
"StatIdentity", "StatIdentity", "StatQq", "StatQqLine", "StatQuantile", |
|
|
1065 |
"StatIdentity", "StatIdentity", "StatIdentity", "StatIdentity", |
|
|
1066 |
"StatIdentity", "StatSf", "StatSmooth", "StatIdentity", "StatIdentity", |
|
|
1067 |
"StatIdentity", "StatIdentity", "StatYdensity", "StatIdentity", |
|
|
1068 |
"StatBin", "StatBin2d", "StatBinhex", "StatBin2d", "StatBinhex", |
|
|
1069 |
"StatBoxplot", "StatContour", "StatCount", "StatDensity", "StatDensity2d", |
|
|
1070 |
"StatDensity2d", "StatEcdf", "StatEllipse", "StatFunction", "StatIdentity", |
|
|
1071 |
"StatQq", "StatQqLine", "StatQuantile", "StatSf", "StatSmooth", |
|
|
1072 |
"StatSum", "StatSummary", "StatSummary2d", "StatSummaryBin", |
|
|
1073 |
"StatSummaryHex", "StatUnique", "StatYdensity"), |
|
|
1074 |
pkg = rep("ggplot2", 77),stringsAsFactors = FALSE) |
|
|
1075 |
)) |
|
|
1076 |
|
|
|
1077 |
# Function to convert color to HCL and adjust components |
|
|
1078 |
#' @importFrom grDevices col2rgb rgb2hsv hcl rgb |
|
|
1079 |
col2hcl <- function(colour, h = NULL, c = NULL, l = NULL, alpha = NULL) { |
|
|
1080 |
# Convert color to RGB |
|
|
1081 |
rgb_col <- grDevices::col2rgb(colour) / 255 |
|
|
1082 |
|
|
|
1083 |
# Convert RGB to HSV |
|
|
1084 |
hsv_col <- grDevices::rgb2hsv(rgb_col) |
|
|
1085 |
|
|
|
1086 |
# Convert HSV to HCL |
|
|
1087 |
hue <- hsv_col[1] * 360 # Convert hue to degrees (0-360) |
|
|
1088 |
chroma <- hsv_col[2] * 100 # Chroma is similar to saturation |
|
|
1089 |
luminance <- hsv_col[3] * 100 # Luminance is related to value |
|
|
1090 |
|
|
|
1091 |
# Allow user to override H, C, or L values |
|
|
1092 |
if (!is.null(h)) hue <- h |
|
|
1093 |
if (!is.null(c)) chroma <- c |
|
|
1094 |
if (!is.null(l)) luminance <- l |
|
|
1095 |
|
|
|
1096 |
# Create the HCL color with potentially modified components |
|
|
1097 |
hcl_col <- grDevices::hcl(h = hue, c = chroma, l = luminance) |
|
|
1098 |
|
|
|
1099 |
# Convert HCL back to RGB to apply alpha |
|
|
1100 |
rgb_col_with_alpha <- grDevices::col2rgb(hcl_col) / 255 |
|
|
1101 |
|
|
|
1102 |
# Add alpha transparency if provided |
|
|
1103 |
if (!is.null(alpha)) { |
|
|
1104 |
rgba_col <- grDevices::rgb(rgb_col_with_alpha[1], rgb_col_with_alpha[2], rgb_col_with_alpha[3], alpha = alpha) |
|
|
1105 |
} else { |
|
|
1106 |
rgba_col <- grDevices::rgb(rgb_col_with_alpha[1], rgb_col_with_alpha[2], rgb_col_with_alpha[3]) |
|
|
1107 |
} |
|
|
1108 |
|
|
|
1109 |
# Return the final RGBA color |
|
|
1110 |
return(rgba_col) |
|
|
1111 |
} |
|
|
1112 |
|
|
|
1113 |
#' @importFrom stats as.formula |
|
|
1114 |
#' @importFrom rlang quo_name |
|
|
1115 |
#' @noRd |
|
|
1116 |
build_map <- function(item,y) { |
|
|
1117 |
|
|
|
1118 |
y <- y[[item]] |
|
|
1119 |
|
|
|
1120 |
if (inherits(y,'quosure')){ |
|
|
1121 |
return(sprintf('%s = %s',item,rlang::quo_name(y))) |
|
|
1122 |
} |
|
|
1123 |
|
|
|
1124 |
if (inherits(y,'character')){ |
|
|
1125 |
return(sprintf("%s = '%s'",item,y)) |
|
|
1126 |
} |
|
|
1127 |
|
|
|
1128 |
if (inherits(y, "formula")){ |
|
|
1129 |
return(sprintf("formula=stats::as.formula('%s')", |
|
|
1130 |
paste0(as.character(y)[-1], collapse = "~"))) |
|
|
1131 |
} |
|
|
1132 |
|
|
|
1133 |
|
|
|
1134 |
if (inherits(y,'NULL')) { |
|
|
1135 |
return(sprintf('%s = NULL',item)) |
|
|
1136 |
} |
|
|
1137 |
|
|
|
1138 |
|
|
|
1139 |
if (inherits(y, c("function", "call", "ggproto"))) { |
|
|
1140 |
return(sprintf("%s = %s", |
|
|
1141 |
item, |
|
|
1142 |
paste(capture.output( |
|
|
1143 |
dput(y)), |
|
|
1144 |
collapse = "\n") |
|
|
1145 |
)) |
|
|
1146 |
} |
|
|
1147 |
|
|
|
1148 |
if (inherits(y, c("data.frame"))) { |
|
|
1149 |
return(paste0("=", paste(capture.output(dput(y)), collapse = "\n"))) |
|
|
1150 |
} |
|
|
1151 |
|
|
|
1152 |
|
|
|
1153 |
return(sprintf('%s = %s',item, y)) |
|
|
1154 |
|
|
|
1155 |
} |
|
|
1156 |
|
|
|
1157 |
#' @noRd |
|
|
1158 |
capture.output <- function (..., file = NULL, append = FALSE, type = c("output", "message"), split = FALSE) |
|
|
1159 |
{ |
|
|
1160 |
type <- match.arg(type) |
|
|
1161 |
rval <- NULL |
|
|
1162 |
closeit <- TRUE |
|
|
1163 |
if (is.null(file)) |
|
|
1164 |
file <- textConnection("rval", "w", local = TRUE) |
|
|
1165 |
else if (is.character(file)) |
|
|
1166 |
file <- file(file, if (append) |
|
|
1167 |
"a" |
|
|
1168 |
else "w") |
|
|
1169 |
else if (inherits(file, "connection")) { |
|
|
1170 |
if (!isOpen(file)) |
|
|
1171 |
open(file, if (append) |
|
|
1172 |
"a" |
|
|
1173 |
else "w") |
|
|
1174 |
else closeit <- FALSE |
|
|
1175 |
} |
|
|
1176 |
else stop("'file' must be NULL, a character string or a connection") |
|
|
1177 |
sink(file, type = type, split = split) |
|
|
1178 |
on.exit({ |
|
|
1179 |
sink(type = type, split = split) |
|
|
1180 |
if (closeit) close(file) |
|
|
1181 |
}) |
|
|
1182 |
for (i in seq_len(...length())) { |
|
|
1183 |
out <- withVisible(...elt(i)) |
|
|
1184 |
if (out$visible) |
|
|
1185 |
print(out$value) |
|
|
1186 |
} |
|
|
1187 |
on.exit() |
|
|
1188 |
sink(type = type, split = split) |
|
|
1189 |
if (closeit) |
|
|
1190 |
close(file) |
|
|
1191 |
if (is.null(rval)) |
|
|
1192 |
invisible(NULL) |
|
|
1193 |
else rval |
|
|
1194 |
} |
|
|
1195 |
|
|
|
1196 |
avgHexColor <- function(colors, ctrlcolor){ |
|
|
1197 |
colors <- lapply(colors, col2rgb) |
|
|
1198 |
rgb(t(Reduce(`+`, colors)/length(colors)), maxColorValue=255) |
|
|
1199 |
} |
|
|
1200 |
|
|
|
1201 |
fill_na_with_preceding <- function(x) { |
|
|
1202 |
if (all(is.na(x))) return(x) |
|
|
1203 |
for (i in 2:length(x)) { |
|
|
1204 |
if (is.na(x[i])) { |
|
|
1205 |
x[i] <- x[i - 1] |
|
|
1206 |
} |
|
|
1207 |
} |
|
|
1208 |
return(x) |
|
|
1209 |
} |