From aa611608611a2141630f793f6b7617bcf77da670 Mon Sep 17 00:00:00 2001 From: Stefano Mangiola Date: Tue, 23 Jan 2024 09:31:57 +1100 Subject: [PATCH 1/5] fix arguments --- DESCRIPTION | 2 +- NAMESPACE | 2 +- R/functions_OLD.R | 1 - R/functions_chr_int.R | 3 +-- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 22bc172..9c4036c 100755 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -20,7 +20,7 @@ Depends: R (>= 3.6.0) Encoding: UTF-8 LazyData: true -RoxygenNote: 7.1.1 +RoxygenNote: 7.3.0 Imports: utils, graphics, diff --git a/NAMESPACE b/NAMESPACE index fc5eadd..8fc5da7 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -21,7 +21,7 @@ importFrom(graphics,par) importFrom(graphics,plot) importFrom(graphics,points) importFrom(lifecycle,deprecate_warn) -importFrom(magrittr,"%>%") +importFrom(magrittr,) importFrom(magrittr,equals) importFrom(magrittr,set_rownames) importFrom(purrr,imap) diff --git a/R/functions_OLD.R b/R/functions_OLD.R index b3970c6..52b4d72 100644 --- a/R/functions_OLD.R +++ b/R/functions_OLD.R @@ -346,7 +346,6 @@ gate_interactive <- #' @param .dim2 A column symbol. The y dimension #' @param gate_list A list of gates. Each element of the list is a data frame with x and y columns. Each row is a coordinate. The order matter. #' @param name A character string. The name of the new column -#' @param ... Further parameters passed to the function gatepoints::fhs #' #' @return A tibble with additional columns #' diff --git a/R/functions_chr_int.R b/R/functions_chr_int.R index 302cbe0..6e735af 100644 --- a/R/functions_chr_int.R +++ b/R/functions_chr_int.R @@ -265,7 +265,7 @@ pretty_plot_chr_int = function(.data, #' @param .size A column symbol. Size of points #' @param opacity A number between 0 and 1. The opacity level of the data points #' @param how_many_gates An integer. The number of gates to label -#' @param gate_list A list of gates. It is returned by gate function as attribute \"gate\". If you want to create this list yourself, each element of the list is a data frame with x and y columns. Each row is a coordinate. The order matter. +#' @param is_size_fixed A logical value indicating if the size of points is fixed, or it is a column name. #' @param ... Further parameters passed to the function gatepoints::fhs #' #' @return A tibble with additional columns @@ -371,7 +371,6 @@ gate_interactive_chr_int <- #' @param .dim1 A column symbol. The x dimension #' @param .dim2 A column symbol. The y dimension #' @param gate_list A list of gates. Each element of the list is a data frame with x and y columns. Each row is a coordinate. The order matter. -#' @param ... Further parameters passed to the function gatepoints::fhs #' #' @return A tibble with additional columns #' From 867f657298ab18dee5c0a47e1dce3681b3b8ff57 Mon Sep 17 00:00:00 2001 From: Stefano Mangiola Date: Tue, 23 Jan 2024 10:52:37 +1100 Subject: [PATCH 2/5] drop when and %>% --- NAMESPACE | 1 - R/functions_OLD.R | 2 +- R/functions_chr_int.R | 404 ++++++++++++++++--------------- R/methods.R | 1 - R/methods_OLD.R | 1 - R/nanny.R | 104 ++++---- R/utilities.R | 99 ++++---- man/gate_interactive_chr_int.Rd | 4 +- man/gate_programmatic.Rd | 2 - man/gate_programmatic_chr_int.Rd | 2 - 10 files changed, 319 insertions(+), 301 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 8fc5da7..12078c1 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -21,7 +21,6 @@ importFrom(graphics,par) importFrom(graphics,plot) importFrom(graphics,points) importFrom(lifecycle,deprecate_warn) -importFrom(magrittr,) importFrom(magrittr,equals) importFrom(magrittr,set_rownames) importFrom(purrr,imap) diff --git a/R/functions_OLD.R b/R/functions_OLD.R index 52b4d72..656c09f 100644 --- a/R/functions_OLD.R +++ b/R/functions_OLD.R @@ -12,7 +12,7 @@ #' @importFrom utils head #' @importFrom stringr str_pad #' @importFrom scales alpha - +#' @importFrom purrr when pretty_plot = function(.data, .dim1, .dim2, diff --git a/R/functions_chr_int.R b/R/functions_chr_int.R index 6e735af..2b16f13 100644 --- a/R/functions_chr_int.R +++ b/R/functions_chr_int.R @@ -3,22 +3,22 @@ parse_gate_list = function(.data, my_df){ # Comply with CRAN NOTES point = NULL - .data %>% - imap( ~ tibble(gate = .y, point = .x)) %>% - reduce(.f = full_join, by = "point") %>% + .data |> + imap( ~ tibble(gate = .y, point = .x)) |> + reduce(.f = full_join, by = "point") |> # Add all points - full_join(tibble(point = as.character(1:nrow(my_df))), by = "point") %>% - arrange(as.numeric(point)) %>% + full_join(tibble(point = as.character(1:nrow(my_df))), by = "point") |> + arrange(as.numeric(point)) |> # Unite in case of a point belonging to multiple gates tidyr::unite(contains("gate"), col = "gate", sep = ",", - na.rm = TRUE) %>% + na.rm = TRUE) |> # Replace NAs - mutate(gate := if_else(gate == "", "0", gate)) %>% + mutate(gate := if_else(gate == "", "0", gate)) |> # Pull pull(gate) @@ -60,100 +60,79 @@ pretty_plot_chr_int = function(.data, my_size_range = c(1, 3) + .data_formatted <- .data + + # Define COLOR + # If not defined + if (pull(.data_formatted, !!.color) |> unique() |> is.na() |> all()) { + .data_formatted <- .data_formatted |> mutate(.color = "grey25", color_hexadecimal = "#3B3B3B") + } + # If continuous + else if (quo_is_symbol(.color) && select(.data_formatted, !!.color) |> sapply(class) |> `%in%`(c("numeric", "integer", "double")) |> any()) { + order_ <- .data_formatted |> pull(!!.color) |> sort() |> findInterval(pull(.data_formatted, !!.color)) + .data_formatted <- .data_formatted |> mutate(color_hexadecimal = grDevices::colorRampPalette(viridis(n = 5))(max(order_))[order_]) + } + # If discrete + else if (quo_is_symbol(.color)) { + how_many_colors <- .data_formatted |> distinct(!!.color) |> nrow() + .data_formatted <- .data_formatted |> mutate(color_hexadecimal = + grDevices::colorRampPalette(RColorBrewer::brewer.pal(min(9, how_many_colors), "Set1"))(how_many_colors)[factor(pull(.data_formatted, !!.color))]) + } + + # Define SIZE + # If not defined + if (pull(.data_formatted, !!.size) |> unique() |> is.na() |> all()) { + .data_formatted <- .data_formatted |> mutate(.size = 2) + } + # If it is a number and not a column name + else if (exists("is_size_fixed") && is_size_fixed) { + .data_formatted <- .data_formatted |> mutate(.size = !!.size) + } + # If continuous + else if (quo_is_symbol(enquo(.size)) && select(.data_formatted, !!enquo(.size)) |> sapply(class) |> `%in%`(c("numeric", "integer", "double")) |> any()) { + .data_formatted <- .data_formatted |> mutate(.size = pull(., !!enquo(.size)) |> rescale(to = my_size_range)) + } + # If discrete + else if (quo_is_symbol(enquo(.size))) { + warning("tidygate says: .size has to be a continuous variable. .size has been ignored") + .data_formatted <- .data_formatted |> mutate(.size = 2) + } + else { + stop("tidygate says: the parameter .size must be NULL, numeric or a symbolic column name") + } + + # Define SHAPE + # If not defined + if (pull(.data_formatted, !!.shape) |> unique() |> is.na() |> all()) { + .data_formatted <- .data_formatted |> mutate(.shape = 19) + } + # If continuous + else if (quo_is_symbol(.shape) && select(.data_formatted, !!.shape) |> sapply(class) |> `%in%`(c("numeric", "integer", "double")) |> any()) { + warning("tidygate says: .shape has to be a discrete variable. .shape has been ignored") + .data_formatted <- .data_formatted |> mutate(.shape = 19) + } + # If discrete + else if (quo_is_symbol(.shape)) { + .data_formatted <- .data_formatted |> mutate(.shape = c(19, 17, 15, 18, 3, 4, 8, 10, 5)[factor(pull(., !!.shape))]) + } - .data_formatted = - .data %>% - - # Define COLOR - when( - - # If not defined - pull(., !!.color) %>% unique %>% is.na() %>% all() ~ (.) %>% mutate(.color = "grey25", color_hexadecimal = "#3B3B3B"), - - # If continuous - quo_is_symbol(.color) && - (.) %>% - select(!!.color) %>% - sapply(class) %in% c("numeric", "integer", "double") ~ { - order_ = findInterval(pull(., !!.color), sort(pull(., !!.color))) - (.) %>% mutate(color_hexadecimal = grDevices::colorRampPalette(viridis(n = 5))(n())[order_]) - }, - - # If discrete - quo_is_symbol(.color) ~ { - how_many_colors = .data %>% distinct(!!.color) %>% nrow - (.) %>% - mutate(color_hexadecimal = - grDevices::colorRampPalette(RColorBrewer::brewer.pal(min( - 9, how_many_colors - ), "Set1"))(how_many_colors)[factor(!!.color)]) - } - ) %>% - - # Define SIZE - when( - # If not defined - pull(., !!.size) %>% unique %>% is.na() %>% all() ~ (.) %>% mutate(.size = 2), - - # If it is a number and not a column name - is_size_fixed ~ (.) %>% mutate(.size := !!.size), - - # If continuous - quo_is_symbol(enquo(.size)) && - (.) %>% - select(!!enquo(.size)) %>% - sapply(class) %in% c("numeric", "integer", "double") ~ (.) %>% mutate(.size := !!enquo(.size) %>% rescale(to = my_size_range)), - - # If discrete - quo_is_symbol(enquo(.size)) ~ { - warning("tidygate says: .size has to be a continuous variable. .size has been ignored") - (.) %>% mutate(.size = 2) - }, - - ~ stop( - "tidygate says: the parameter .size must be NULL, numeric or a symbolic column name" - ) - ) %>% - - # Define SHAPE - when( - - # If not defined - pull(., !!.shape) %>% unique %>% is.na() %>% all() ~ (.) %>% mutate(.shape = 19), - - # If continuous - quo_is_symbol(.shape) & - (.) %>% - select(!!.shape) %>% - sapply(class) %in% c("numeric", "integer", "double") ~ { - warning("tidygate says: .shape has to be a discrete variable. .shape has been ignored") - (.) %>% mutate(.shape = 19) - } , - - # If discrete - quo_is_symbol(.shape) ~ (.) %>% mutate(.shape := c(19, 17, 15, 18, 3, 4, 8, 10, 5)[factor(!!.shape)]) - - - ) # Plot - .data_formatted %>% - { - plot( - (.) %>% pull(!!.dim1), - (.) %>% pull(!!.dim2), - xlim = range((.) %>% pull(!!.dim1)), - ylim = range((.) %>% pull(!!.dim2)), + plot( + .data_formatted |> pull(!!.dim1), + .data_formatted |> pull(!!.dim2), + xlim = range(.data_formatted |> pull(!!.dim1)), + ylim = range(.data_formatted |> pull(!!.dim2)), bty = 'l', - pch = (.) %>% pull(.shape), - cex = (.) %>% pull(.size), - col = (.) %>% pull(color_hexadecimal) %>% alpha(opacity), - xlab = quo_names(.dim1) %>% paste(collapse = " "), - ylab = quo_names(.dim2) %>% paste(collapse = " "), + pch = .data_formatted |> pull(.shape), + cex = .data_formatted |> pull(.size), + col = .data_formatted |> pull(color_hexadecimal) |> alpha(opacity), + xlab = quo_names(.dim1) |> paste(collapse = " "), + ylab = quo_names(.dim2) |> paste(collapse = " "), xaxt = 'n', yaxt = 'n' ) - } + axis(1, tck = 1, col.ticks = "light gray") axis(1, @@ -186,37 +165,67 @@ pretty_plot_chr_int = function(.data, # Add legend to top right, outside plot region inset_y = 0 - if (pull(.data, !!.color) %>% unique %>% is.na() %>% not() %>% all()) { + + # Check if the 'color' column in .data is not all NA (missing values) + if (pull(.data, !!.color) |> unique() |> is.na() |> not() |> all()) { + + # Get the class/type of the 'color' column in .data_formatted + color_class <- pull(.data_formatted, !!.color) |> class() + + # If the 'color' column is of numeric, integer, or double type (continuous data) + if (color_class %in% c("numeric", "integer", "double")) { + # Create a legend for continuous color data + color_legend <- .data_formatted |> + arrange(!!.color) |> + slice(1, n()) |> + pull(!!.color) |> + round(digits = 4) + color_col <- .data_formatted |> + arrange(!!.color) |> + slice(1, n()) |> + pull(color_hexadecimal) + } else { + # Create a legend for non-continuous (discrete) color data + color_legend <- .data_formatted |> + arrange(!!.color) |> + distinct(!!.color) |> + pull(!!.color) + color_col <- .data_formatted |> + arrange(!!.color) |> + distinct(color_hexadecimal) |> + pull(color_hexadecimal) + } + + # Add the color legend to the plot legend( "topleft", inset = c(1.05, inset_y), - legend = .data_formatted %>% - - # If continuous - when( - pull(., !!.color) %>% class %in% c("numeric", "integer", "double") ~ arrange(., !!.color) %>% slice(1, n()) %>% pull(!!.color) %>% round(digits = 4), - ~ arrange(., !!.color) %>% distinct(!!.color) %>% pull(!!.color) - ), + legend = color_legend, pch = 19, - col = .data_formatted %>% - - # If continuous - when( - pull(., !!.color) %>% class %in% c("numeric", "integer", "double") ~ arrange(., !!.color) %>% slice(1, n()) %>% pull(color_hexadecimal), - ~ arrange(., !!.color) %>% distinct(color_hexadecimal) %>% pull(color_hexadecimal) - ), + col = color_col, title = color_title, box.col = "white", xjust = 0 ) - inset_y = inset_y + distinct(.data_formatted,!!.color, .color) %>% nrow %>% magrittr::multiply_by(.1) + + # Adjust the position for the next legend + inset_y <- inset_y + (.data_formatted |> distinct(!!.color, .color) |> nrow() * 0.1) } - if (pull(.data, !!.size) %>% unique %>% is.na() %>% not() %>% all() && - (.data %>% select(!!enquo(.size)) %>% sapply(class) %in% c("numeric", "integer", "double"))) { + + # Check if the 'size' column in .data is not all NA and is numeric + if (pull(.data, !!.size) |> unique() |> is.na() |> not() |> all() && + (.data |> select(!!enquo(.size)) |> sapply(class) |> `%in%`(c("numeric", "integer", "double")) |> any())) { + # Create a legend for the size variable + size_legend <- .data_formatted |> + distinct(!!enquo(.size)) |> + pull(!!enquo(.size)) |> + range() + + # Add the size legend to the plot legend( "topleft", inset = c(1.05, inset_y), - legend = distinct(.data_formatted,!!enquo(.size)) %>% pull(!!enquo(.size)) %>% range, + legend = size_legend, pch = 19, col = "black", pt.cex = my_size_range, @@ -224,20 +233,31 @@ pretty_plot_chr_int = function(.data, box.col = "white", xjust = 0 ) - inset_y = inset_y + 0.3 + + # Adjust the position for the next legend + inset_y <- inset_y + 0.3 } - if (pull(.data, !!.shape) %>% unique %>% is.na() %>% not() %>% all()) { + + # Check if the 'shape' column in .data is not all NA + if (pull(.data, !!.shape) |> unique() |> is.na() |> not() |> all()) { + # Create a legend for the shape variable + shape_legend <- .data |> distinct(!!.shape) |> pull(!!.shape) + shape_pch <- .data_formatted |> distinct(!!.shape, .shape) |> pull(.shape) + + # Add the shape legend to the plot legend( "topleft", inset = c(1.05, inset_y), - legend = distinct(.data,!!.shape) %>% pull(!!.shape), - pch = distinct(.data_formatted,!!.shape, .shape) %>% pull(.shape), + legend = shape_legend, + pch = shape_pch, col = "black", title = shape_title, box.col = "white", yjust = 0 ) - inset_y = inset_y + distinct(.data_formatted,!!.shape, .shape) %>% nrow %>% magrittr::multiply_by(.1) + + # Adjust the position for the next legend + inset_y <- inset_y + (.data_formatted |> distinct(!!.shape, .shape) |> nrow() * 0.1) } @@ -294,25 +314,20 @@ gate_interactive_chr_int <- name = "gate" - # my df - my_df = - .data %>% - - # Check if dimensions are NA - check_dimensions(!!.dim1,!!.dim2) + # Check if dimensions are NA and create my_df + my_df <- .data |> + check_dimensions(!!.dim1, !!.dim2) - my_matrix = - my_df %>% - select(!!.dim1,!!.dim2) %>% - .as_matrix() + # Create my_matrix from my_df + my_matrix <- my_df |> + select(!!.dim1, !!.dim2) |> + as.matrix() # Add extra space to right of plot area; change clipping to figure - if (pull(.data, !!.color) %>% unique %>% is.na() %>% not() %>% all() | - pull(.data, !!.shape) %>% unique %>% is.na() %>% not() %>% all()| - (pull(.data, !!.size) %>% unique %>% is.na() %>% not() %>% all() && - ( - .data %>% select(!!.size) %>% sapply(class) %in% c("numeric", "integer", "double") - ))) { + if ((pull(.data, !!.color) |> unique() |> is.na() |> not() |> all()) | + (pull(.data, !!.shape) |> unique() |> is.na() |> not() |> all()) | + (pull(.data, !!.size) |> unique() |> is.na() |> not() |> all() && + (.data |> select(!!.size) |> sapply(class) |> `%in%`(c("numeric", "integer", "double")) |> any()))) { # Reset par on exit opar <- par(no.readonly = TRUE) on.exit(par(opar)) @@ -320,42 +335,36 @@ gate_interactive_chr_int <- # Set the new par par(mar = c(5.1, 4.1, 4.1, 8.1), xpd = TRUE, - - # Reduce tick length - tck = -.01 - ) + tck = -.01) # Reduce tick length } - # Plot - my_df %>% pretty_plot_chr_int( - !!.dim1,!!.dim2, - .color = !!.color, - .shape = !!.shape, - - # size can be number or column - .size = !!.size, - - opacity = opacity, - is_size_fixed = is_size_fixed - ) + my_df |> + pretty_plot_chr_int( + !!.dim1, !!.dim2, + .color = !!.color, + .shape = !!.shape, + .size = !!.size, + opacity = opacity, + is_size_fixed = is_size_fixed + ) - # Loop over gates # Variable needed for recalling the attributes later - gate_list = map(1:how_many_gates, - ~ my_matrix %>% fhs(mark = TRUE, ...)) + # Loop over gates and create gate_list + gate_list <- map(1:how_many_gates, + ~ my_matrix |> fhs(mark = TRUE, ...)) # Save gate list - temp_file = sprintf("%s.rds", tempfile()) + temp_file <- sprintf("%s.rds", tempfile()) message(sprintf("tidygate says: the gates have been saved in %s", temp_file)) - gate_list %>% - map(~ attr(.x, "gate")) %>% + gate_list |> + map(~ attr(.x, "gate")) |> saveRDS(temp_file) - # Return - gate_list %>% parse_gate_list(my_df) - + # Return the parsed gate list + gate_list |> parse_gate_list(my_df) } + #' Get points within a user drawn gate #' #' @keywords internal @@ -391,29 +400,43 @@ gate_programmatic_chr_int <- # my df my_df = - .data %>% + .data |> # Check if dimensions are NA check_dimensions(!!.dim1,!!.dim2) my_matrix = - my_df %>% - select(!!.dim1,!!.dim2) %>% + my_df |> + select(!!.dim1,!!.dim2) |> .as_matrix() # Loop over gates # Variable needed for recalling the attributes later - gate_list_result = map(gate_list, - ~ .x %>% - when("data.frame" %in% class(.) ~ .as_matrix(.), ~ (.)) %>% - applyGate(my_matrix, .) %>% - which() %>% - as.character() %>% - - # Avoid error for empty gates - when(!is.null(.) ~ (.) %>% add_attr(.x, "gate"))) + # Loop over gates + gate_list_result <- map(gate_list, function(.x) { + # Check the class of the item + if ("data.frame" %in% class(.x)) { + result <- .as_matrix(.x) + } else { + result <- .x + } + + # Apply gate and convert to character + result <- applyGate(my_matrix, result) |> + which() |> + as.character() + + # Avoid error for empty gates + if (!is.null(result)) { + result <- result |> + add_attr(.x, "gate") + } + + return(result) + }) + # Return - gate_list_result %>% + gate_list_result |> parse_gate_list(my_df) @@ -439,15 +462,13 @@ gate_programmatic_chr_int <- point = NULL # If gouping is complex multicolumn - .group_by = - .group_by %>% - when( - !is.null(.group_by) ~ matrix(ncol = length(.group_by) / length(.dim1)) %>% - as.data.frame() %>% - unite(".group_by", everything(), sep = "___") %>% - pull(.group_by), - ~ (.) - ) + if (!is.null(.group_by)) { + .group_by <- .group_by |> + matrix(ncol = length(.group_by) / length(.dim1)) |> + as.data.frame() |> + unite(".group_by", everything(), sep = "___") |> + pull(.group_by) + } # Create tibble @@ -464,14 +485,15 @@ gate_programmatic_chr_int <- if(!is.null(.group_by)) input_df = input_df |> mutate(., .group_by = !!.group_by) - unique_df = - input_df %>% - - # Nesting is the case - when(!is.null(.group_by) ~ nest(., data___ = .group_by), - (.)) %>% - - distinct() + if (!is.null(.group_by)) { + unique_df <- input_df |> + nest(data___ = .group_by) + } else { + unique_df <- input_df + } + + # Apply 'distinct()' outside of the if-else block + unique_df <- unique_df |> distinct() # Interactive if(is.null(gate_list)) @@ -515,9 +537,9 @@ gate_programmatic_chr_int <- else if(output_type == "int") result_vector = result_vector |> as.integer() # Integrate maintaining order in case of nesting - input_df %>% + input_df |> left_join( - unique_df %>% + unique_df |> mutate(gate = result_vector) ) |> suppressMessages() |> diff --git a/R/methods.R b/R/methods.R index 48ad11c..aac5ee8 100755 --- a/R/methods.R +++ b/R/methods.R @@ -6,7 +6,6 @@ #' #' @importFrom rlang enquo #' @importFrom rlang quo_is_null -#' @importFrom magrittr "%>%" #' #' @name gate_chr #' diff --git a/R/methods_OLD.R b/R/methods_OLD.R index 9a11f8e..565b166 100644 --- a/R/methods_OLD.R +++ b/R/methods_OLD.R @@ -7,7 +7,6 @@ #' @description gate() takes as input a `tbl` formatted as | | | <...> | and calculates the rotated dimensional space of the feature value. #' #' @importFrom rlang enquo -#' @importFrom magrittr "%>%" #' @importFrom lifecycle deprecate_warn #' #' @name gate diff --git a/R/nanny.R b/R/nanny.R index c85d003..1eb5801 100755 --- a/R/nanny.R +++ b/R/nanny.R @@ -32,24 +32,27 @@ get_specific_annotation_columns = function(.data, .col){ n_x = .data %>% distinct_at(vars(!!.col)) %>% nrow # element wise columns - .data %>% - select(-!!.col) %>% - colnames %>% + .data = + .data |> + select(-!!.col) |> + colnames() |> map( - ~ - .x %>% - when( - .data %>% - distinct_at(vars(!!.col, .x)) %>% - nrow %>% - equals(n_x) ~ .x, - ~ NULL - ) - ) %>% - - # Drop NULL - { (.)[lengths((.)) != 0] } %>% - unlist + ~ { + current_col <- .x + # Check condition + if (nrow(.data |> distinct_at(vars(!!.col, current_col))) == n_x) { + result <- current_col + } else { + result <- NULL + } + result + } + ) + + # Drop null + .data[lengths(.data) != 0] |> + unlist() + } @@ -58,54 +61,41 @@ get_specific_annotation_columns = function(.data, .col){ #' @importFrom magrittr set_rownames #' @importFrom rlang quo_is_null #' @importFrom rlang quo_is_symbolic -#' @importFrom purrr when -.as_matrix = function(.data, - rownames = NULL, - do_check = TRUE, - sep_rownames = "___") { - +.as_matrix = function(.data, rownames = NULL, do_check = TRUE, sep_rownames = "___") { # Comply with CRAN NOTES variable = NULL rownames = enquo(rownames) - - .data %>% - - # Through warning if data frame is not numerical beside the rownames column (if present) - when( - do_check && - (.) %>% - # If rownames defined eliminate it from the data frame - when(!quo_is_null(rownames) ~ (.) %>% select(-!!rownames), ~ (.)) %>% - dplyr::summarise_all(class) %>% - tidyr::gather(variable, class) %>% - pull(class) %>% - unique() %>% - `%in%`(c("numeric", "integer")) %>% `!`() %>% any() ~ { - warning("tidygate says: there are NON-numerical columns, the matrix will NOT be numerical") - (.) - }, - ~ (.) - ) %>% - - # If rownames multiple enquo (e.g., c(col1, col2)) merge them - when(!quo_is_null(rownames) ~ (.) %>% unite(col = "rn", !!rownames, sep = sep_rownames), ~ (.)) %>% + # Process data based on conditions + if (do_check) { + if (!quo_is_null(rownames)) { + # If rownames are not null, select columns except rownames + .data <- .data |> select(-!!rownames) + } - as.data.frame() %>% - - # Deal with rownames column if present - when( - !quo_is_null(rownames) ~ (.) %>% - set_rownames((.) %>% pull(rn)) %>% - select(-rn), - ~ (.) - ) %>% - - # Convert to matrix - as.matrix() + # Check for non-numeric columns + if (any(!unique(.data |> summarise_all(class) |> gather(variable, class) |> pull(class)) %in% c("numeric", "integer"))) { + warning("tidygate says: there are NON-numerical columns, the matrix will NOT be numerical") + } + } + + # Merge columns for rownames if rownames are not null + if (!quo_is_null(rownames)) { + .data <- .data |> unite(col = "rn", !!rownames, sep = sep_rownames) + } + + # Convert to data frame and then to matrix, handling rownames if present + if (!quo_is_null(rownames)) { + .data <- .data |> + set_rownames(pull(.data, rn)) |> + select(-rn) + } + + .data |> as.matrix() } + #' Convert array of quosure (e.g. c(col_a, col_b)) into character vector #' #' @keywords internal diff --git a/R/utilities.R b/R/utilities.R index af16d5a..16261ed 100755 --- a/R/utilities.R +++ b/R/utilities.R @@ -1,35 +1,48 @@ # Negation not = function(is){ !is } -check_data_unique = function(.data, - .element, - .dim1, - .dim2) { - # Get column names +check_data_unique = function(.data, .element, .dim1, .dim2) { + # Get column names as quosures .element = enquo(.element) .dim1 = enquo(.dim1) .dim2 = enquo(.dim2) - if (.data %>% - select(!!.element,!!.dim1,!!.dim2) %>% - distinct %>% - - # Count - group_by_at(vars(!!.element,!!.dim1,!!.dim2)) %>% - tally() %>% - ungroup() %>% - - # Check - pull(n) %>% - max %>% - `>` (1)) - stop(sprintf( - "tidygate says: %s must be unique for each row for the calculation", - quo_names(.element) - )) + # Check if the combination of .element, .dim1, and .dim2 is unique for each row + if ( + # Select the specified columns + .data |> + select(!!.element, !!.dim1, !!.dim2) |> + + # Remove duplicate rows + distinct() |> + + # Group by these columns + group_by_at(vars(!!.element, !!.dim1, !!.dim2)) |> + + # Count the number of rows in each group + tally() |> + + # Remove the grouping + ungroup() |> + + # Extract the count column + pull(n) |> + + # Check if the maximum count is greater than 1 + max() > 1 + ) { + + # If duplicates are found, stop the function and return an error message + stop(sprintf( + "tidygate says: %s must be unique for each row for the calculation", + quo_names(.element) + )) + } } + + reattach_internals = function(.data, .data_internals_from = NULL, .name = "gate") { @@ -58,29 +71,29 @@ check_dimensions = function(.data, .dim1, .dim2) { .dim1 = enquo(.dim1) .dim2 = enquo(.dim2) - .data %>% - when(# If NAs in dimensions - (.) %>% - filter(!!.dim1 %>% is.na | !!.dim2 %>% is.na) %>% - nrow() %>% - `>` (0) ~ { - warning( - "tidygate says: you have some elements with non-valid dimensions. Those elements points will be filtered out" - ) - (.) %>% - filter(!!.dim1 %>% is.na | !!.dim2 %>% is.na) %>% - capture.output() %>% - paste0(collapse = "\n") %>% - message() - - # Return - (.) %>% filter(!(!!.dim1 %>% is.na | !!.dim2 %>% is.na)) - }, - - # Otherwise - ~ (.)) + # Check if there are NAs in dimensions + if ( + .data |> + filter( is.na(!!.dim1) | is.na(!!.dim2)) |> + nrow() > 0 + ) { + warning("tidygate says: you have some elements with non-valid dimensions. Those elements points will be filtered out") + + # Capture and message the filtered data + filtered_data <- .data |> + filter(is.na(!!.dim1) | is.na(!!.dim2)) + capture_output <- capture.output(print(filtered_data)) |> + paste0(collapse = "\n") |> + message() + + # Filter out non-valid elements + .data <- .data |> filter(!is.na(!!.dim1) & !is.na(!!.dim2)) + } + + return(.data) } + format_gatepoints = function(.data, .element, name, .idx) { # Comply CRAN check value = NULL diff --git a/man/gate_interactive_chr_int.Rd b/man/gate_interactive_chr_int.Rd index 23c828e..965ce7c 100644 --- a/man/gate_interactive_chr_int.Rd +++ b/man/gate_interactive_chr_int.Rd @@ -34,9 +34,9 @@ gate_interactive_chr_int( \item{how_many_gates}{An integer. The number of gates to label} -\item{...}{Further parameters passed to the function gatepoints::fhs} +\item{is_size_fixed}{A logical value indicating if the size of points is fixed, or it is a column name.} -\item{gate_list}{A list of gates. It is returned by gate function as attribute \"gate\". If you want to create this list yourself, each element of the list is a data frame with x and y columns. Each row is a coordinate. The order matter.} +\item{...}{Further parameters passed to the function gatepoints::fhs} } \value{ A tibble with additional columns diff --git a/man/gate_programmatic.Rd b/man/gate_programmatic.Rd index 59999f4..ed228f4 100644 --- a/man/gate_programmatic.Rd +++ b/man/gate_programmatic.Rd @@ -18,8 +18,6 @@ gate_programmatic(.data, .element, .dim1, .dim2, gate_list, name = "gate") \item{gate_list}{A list of gates. Each element of the list is a data frame with x and y columns. Each row is a coordinate. The order matter.} \item{name}{A character string. The name of the new column} - -\item{...}{Further parameters passed to the function gatepoints::fhs} } \value{ A tibble with additional columns diff --git a/man/gate_programmatic_chr_int.Rd b/man/gate_programmatic_chr_int.Rd index 91537de..fe3a506 100644 --- a/man/gate_programmatic_chr_int.Rd +++ b/man/gate_programmatic_chr_int.Rd @@ -14,8 +14,6 @@ gate_programmatic_chr_int(.data, .dim1, .dim2, gate_list) \item{.dim2}{A column symbol. The y dimension} \item{gate_list}{A list of gates. Each element of the list is a data frame with x and y columns. Each row is a coordinate. The order matter.} - -\item{...}{Further parameters passed to the function gatepoints::fhs} } \value{ A tibble with additional columns From 1fd713ce02f8c28793371f02cceb7ddd02b56675 Mon Sep 17 00:00:00 2001 From: Stefano Mangiola Date: Tue, 23 Jan 2024 11:18:36 +1100 Subject: [PATCH 3/5] solving further errors due to conversion --- NAMESPACE | 2 ++ R/functions_OLD.R | 1 + R/methods.R | 10 +++++----- R/nanny.R | 24 +++++++++++++++--------- R/utilities.R | 13 +++++++------ man/gate_chr-methods.Rd | 10 +++++----- tests/testthat/test-methods.R | 24 ++++++++++++------------ 7 files changed, 47 insertions(+), 37 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 12078c1..5c9ab96 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -21,6 +21,7 @@ importFrom(graphics,par) importFrom(graphics,plot) importFrom(graphics,points) importFrom(lifecycle,deprecate_warn) +importFrom(magrittr,"%>%") importFrom(magrittr,equals) importFrom(magrittr,set_rownames) importFrom(purrr,imap) @@ -37,5 +38,6 @@ importFrom(rlang,quo_squash) importFrom(scales,alpha) importFrom(scales,rescale) importFrom(stringr,str_pad) +importFrom(utils,capture.output) importFrom(utils,head) importFrom(viridis,viridis) diff --git a/R/functions_OLD.R b/R/functions_OLD.R index 656c09f..4993331 100644 --- a/R/functions_OLD.R +++ b/R/functions_OLD.R @@ -13,6 +13,7 @@ #' @importFrom stringr str_pad #' @importFrom scales alpha #' @importFrom purrr when +#' @importFrom magrittr %>% pretty_plot = function(.data, .dim1, .dim2, diff --git a/R/methods.R b/R/methods.R index aac5ee8..12b9d67 100755 --- a/R/methods.R +++ b/R/methods.R @@ -33,8 +33,8 @@ #' #' if(interactive()){ #' -#' tidygate::tidygate_data %>% -#' distinct(`ct 1` , `ct 2`, Dim1, Dim2) %>% +#' tidygate::tidygate_data |> +#' distinct(`ct 1` , `ct 2`, Dim1, Dim2) |> #' mutate(gate = gate_chr( Dim1, Dim2)) #' #' } @@ -46,13 +46,13 @@ #' #' # Standard use - programmatic #' res_distinct = -#' tidygate::tidygate_data %>% -#' distinct(`ct 1` , `ct 2`, Dim1, Dim2) %>% +#' tidygate::tidygate_data |> +#' distinct(`ct 1` , `ct 2`, Dim1, Dim2) |> #' mutate(gate = gate_chr( Dim1, Dim2,gate_list = tidygate::gate_list)) #' #' # Grouping - programmatic #' res = -#' tidygate::tidygate_data %>% +#' tidygate::tidygate_data |> #' mutate(gate = gate_chr( #' Dim1, Dim2, #' .group_by = c(`ct 1` , `ct 2`), diff --git a/R/nanny.R b/R/nanny.R index 1eb5801..a7a425b 100755 --- a/R/nanny.R +++ b/R/nanny.R @@ -12,9 +12,9 @@ quo_names <- function(v) { v = quo_name(quo_squash(v)) - gsub('^c\\(|`|\\)$', '', v) %>% - strsplit(', ') %>% - unlist + gsub('^c\\(|`|\\)$', '', v) |> + strsplit(', ') |> + unlist() } #' @importFrom magrittr equals @@ -29,7 +29,7 @@ get_specific_annotation_columns = function(.data, .col){ .col = enquo(.col) # x-annotation df - n_x = .data %>% distinct_at(vars(!!.col)) %>% nrow + n_x = .data |> distinct_at(vars(!!.col)) |> nrow() # element wise columns .data = @@ -62,20 +62,24 @@ get_specific_annotation_columns = function(.data, .col){ #' @importFrom rlang quo_is_null #' @importFrom rlang quo_is_symbolic .as_matrix = function(.data, rownames = NULL, do_check = TRUE, sep_rownames = "___") { + # Comply with CRAN NOTES variable = NULL + rn = NULL rownames = enquo(rownames) # Process data based on conditions if (do_check) { + .data_check = .data + if (!quo_is_null(rownames)) { # If rownames are not null, select columns except rownames - .data <- .data |> select(-!!rownames) + .data_check <- .data_check |> select(-!!rownames) } # Check for non-numeric columns - if (any(!unique(.data |> summarise_all(class) |> gather(variable, class) |> pull(class)) %in% c("numeric", "integer"))) { + if (any(!unique(.data_check |> summarise_all(class) |> gather(variable, class) |> pull(class)) %in% c("numeric", "integer"))) { warning("tidygate says: there are NON-numerical columns, the matrix will NOT be numerical") } } @@ -85,6 +89,8 @@ get_specific_annotation_columns = function(.data, .col){ .data <- .data |> unite(col = "rn", !!rownames, sep = sep_rownames) } + .data = .data |> as.data.frame() + # Convert to data frame and then to matrix, handling rownames if present if (!quo_is_null(rownames)) { .data <- .data |> @@ -109,7 +115,7 @@ get_specific_annotation_columns = function(.data, .col){ quo_names <- function(v) { v = quo_name(quo_squash(v)) - gsub('^c\\(|`|\\)$', '', v) %>% - strsplit(', ') %>% - unlist + gsub('^c\\(|`|\\)$', '', v) |> + strsplit(', ') |> + unlist() } \ No newline at end of file diff --git a/R/utilities.R b/R/utilities.R index 16261ed..feb9158 100755 --- a/R/utilities.R +++ b/R/utilities.R @@ -46,10 +46,10 @@ check_data_unique = function(.data, .element, .dim1, .dim2) { reattach_internals = function(.data, .data_internals_from = NULL, .name = "gate") { - if (.data_internals_from %>% is.null) + if (.data_internals_from |> is.null()) .data_internals_from = .data - .data %>% add_attr(.data_internals_from %>% attr(.name), .name) + .data |> add_attr(.data_internals_from |> attr(.name), .name) } #' Add attribute to abject @@ -67,6 +67,7 @@ add_attr = function(var, attribute, name) { var } +#' @importFrom utils capture.output check_dimensions = function(.data, .dim1, .dim2) { .dim1 = enquo(.dim1) .dim2 = enquo(.dim2) @@ -101,12 +102,12 @@ format_gatepoints = function(.data, .element, name, .idx) { # Column name .element = enquo(.element) - .data %>% - as.character %>% - as_tibble() %>% + .data |> + as.character() |> + as_tibble() |> # Reconstitute columns - separate(value, quo_names(.element), sep = "___") %>% + separate(value, quo_names(.element), sep = "___") |> mutate(!!as.symbol(sprintf("%s%s", name, .idx)) := .idx) } diff --git a/man/gate_chr-methods.Rd b/man/gate_chr-methods.Rd index a8f71c1..a4b591b 100644 --- a/man/gate_chr-methods.Rd +++ b/man/gate_chr-methods.Rd @@ -73,8 +73,8 @@ This function allow the user to label data points in inside one or more 2D gates if(interactive()){ - tidygate::tidygate_data \%>\% - distinct(`ct 1` , `ct 2`, Dim1, Dim2) \%>\% + tidygate::tidygate_data |> + distinct(`ct 1` , `ct 2`, Dim1, Dim2) |> mutate(gate = gate_chr( Dim1, Dim2)) } @@ -86,13 +86,13 @@ library(dplyr) # Standard use - programmatic res_distinct = - tidygate::tidygate_data \%>\% - distinct(`ct 1` , `ct 2`, Dim1, Dim2) \%>\% + tidygate::tidygate_data |> + distinct(`ct 1` , `ct 2`, Dim1, Dim2) |> mutate(gate = gate_chr( Dim1, Dim2,gate_list = tidygate::gate_list)) # Grouping - programmatic res = - tidygate::tidygate_data \%>\% + tidygate::tidygate_data |> mutate(gate = gate_chr( Dim1, Dim2, .group_by = c(`ct 1` , `ct 2`), diff --git a/tests/testthat/test-methods.R b/tests/testthat/test-methods.R index 656bcd8..e0b1228 100755 --- a/tests/testthat/test-methods.R +++ b/tests/testthat/test-methods.R @@ -3,8 +3,8 @@ # test_that("gate dimensions", { # library(dplyr) # res = -# tidygate::tidygate_data %>% -# mutate(sh = factor(hierarchy)) %>% +# tidygate::tidygate_data |> +# mutate(sh = factor(hierarchy)) |> # mutate( # gate = gate_chr( # Dim1, Dim2, @@ -17,8 +17,8 @@ # # res2 = -# tidygate::tidygate_data %>% -# mutate(sh = factor(hierarchy)) %>% +# tidygate::tidygate_data |> +# mutate(sh = factor(hierarchy)) |> # gate( # .element = c(`ct 1`, `ct 2`), # Dim1, Dim2, @@ -33,8 +33,8 @@ test_that("gate dimensions", { library(dplyr) res = - tidygate::tidygate_data %>% - distinct(`ct 1` , `ct 2`, Dim1, Dim2) %>% + tidygate::tidygate_data |> + distinct(`ct 1` , `ct 2`, Dim1, Dim2) |> mutate(gate = gate_chr( Dim1, Dim2,gate_list = tidygate::gate_list)) @@ -42,8 +42,8 @@ test_that("gate dimensions", { res = - tidygate::tidygate_data %>% - distinct(`ct 1` , `ct 2`, Dim1, Dim2) %>% + tidygate::tidygate_data |> + distinct(`ct 1` , `ct 2`, Dim1, Dim2) |> mutate(gate = gate_int(Dim1, Dim2, gate_list = tidygate::gate_list)) expect_equal(ncol(res) , 5) @@ -54,13 +54,13 @@ test_that("gate grouping", { library(dplyr) res_distinct = - tidygate::tidygate_data %>% - distinct(`ct 1` , `ct 2`, Dim1, Dim2) %>% + tidygate::tidygate_data |> + distinct(`ct 1` , `ct 2`, Dim1, Dim2) |> mutate(gate = gate_chr( Dim1, Dim2,gate_list = tidygate::gate_list)) res = - tidygate::tidygate_data %>% - mutate(gate = gate_chr( Dim1, Dim2, .group_by = c(`ct 1` , `ct 2`), gate_list = tidygate::gate_list)) %>% + tidygate::tidygate_data |> + mutate(gate = gate_chr( Dim1, Dim2, .group_by = c(`ct 1` , `ct 2`), gate_list = tidygate::gate_list)) |> distinct(`ct 1` , `ct 2`, Dim1, Dim2, gate) From d1e0d2f2cdc6ae24728e5d028129fcbb50ec6a5e Mon Sep 17 00:00:00 2001 From: Stefano Mangiola Date: Tue, 23 Jan 2024 11:18:43 +1100 Subject: [PATCH 4/5] version UP --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 9c4036c..0fc176f 100755 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: tidygate Type: Package Title: Add Gate Information to Your Tibble -Version: 0.4.9 +Version: 0.4.10 Authors@R: c(person(given = "Stefano", family = "Mangiola", From 5f22c170d0fdcbf25af464c0e9d7d3b822aabdbb Mon Sep 17 00:00:00 2001 From: Stefano Mangiola Date: Tue, 23 Jan 2024 11:21:45 +1100 Subject: [PATCH 5/5] use rworkflows --- .github/workflows/R-CMD-check.yaml | 103 ----------------------------- .github/workflows/rworkflows.yml | 57 ++++++++++++++++ 2 files changed, 57 insertions(+), 103 deletions(-) delete mode 100644 .github/workflows/R-CMD-check.yaml create mode 100644 .github/workflows/rworkflows.yml diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml deleted file mode 100644 index 2420e65..0000000 --- a/.github/workflows/R-CMD-check.yaml +++ /dev/null @@ -1,103 +0,0 @@ -# For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag. -# https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions -on: - push: - branches: - - dev - - master - pull_request: - branches: - - dev - - master - -name: R-CMD-check - -jobs: - R-CMD-check: - runs-on: ${{ matrix.config.os }} - - name: ${{ matrix.config.os }} (${{ matrix.config.r }}) - - strategy: - fail-fast: false - matrix: - config: - - {os: windows-latest, r: 'release'} - - {os: macOS-latest, r: 'release'} - - {os: ubuntu-20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"} - # - {os: ubuntu-20.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"} - - env: - R_REMOTES_NO_ERRORS_FROM_WARNINGS: true - RSPM: ${{ matrix.config.rspm }} - - steps: - - uses: actions/checkout@v2 - - - uses: r-lib/actions/setup-r@v1 - with: - r-version: ${{ matrix.config.r }} - - - uses: r-lib/actions/setup-pandoc@v1 - - - name: Query dependencies - run: | - install.packages('remotes') - saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) - writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") - shell: Rscript {0} - - - name: Cache R packages - if: runner.os != 'Windows' - uses: actions/cache@v2 - with: - path: ${{ env.R_LIBS_USER }} - key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} - restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- - - - name: Install system dependencies - if: runner.os == 'Linux' - run: | - while read -r cmd - do - eval sudo $cmd - done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "20.04"))') - - - name: Install dependencies - run: | - remotes::install_deps(dependencies = TRUE) - remotes::install_cran("rcmdcheck") - shell: Rscript {0} - - - name: Check - env: - _R_CHECK_CRAN_INCOMING_REMOTE_: false - _R_CHECK_FORCE_SUGGESTS_ : false - run: rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), build_args = "--no-manual", error_on = "warning", check_dir = "check") - shell: Rscript {0} - - - name: Install pkgdown - if: github.ref == 'refs/heads/master' && runner.os == 'Linux' - run: | - remotes::install_deps(dependencies = TRUE) - install.packages("pkgdown") - shell: Rscript {0} - - - name: Install package - if: github.ref == 'refs/heads/master' && runner.os == 'Linux' - run: R CMD INSTALL . - - - name: Deploy package - if: github.ref == 'refs/heads/master' && runner.os == 'Linux' - run: | - git config --local user.email "actions@github.com" - git config --local user.name "GitHub Actions" - Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)' - shell: bash {0} - - - name: Upload check results - if: failure() - uses: actions/upload-artifact@main - with: - name: ${{ runner.os }}-r${{ matrix.config.r }}-results - path: check diff --git a/.github/workflows/rworkflows.yml b/.github/workflows/rworkflows.yml new file mode 100644 index 0000000..94d43eb --- /dev/null +++ b/.github/workflows/rworkflows.yml @@ -0,0 +1,57 @@ +name: rworkflows +'on': + push: + branches: + - master + - main + - devel + - RELEASE_** + pull_request: + branches: + - master + - main + - devel + - RELEASE_** +jobs: + rworkflows: + permissions: write-all + runs-on: ${{ matrix.config.os }} + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + container: ${{ matrix.config.cont }} + strategy: + fail-fast: ${{ false }} + matrix: + config: + - os: ubuntu-latest + bioc: devel + r: auto + cont: ghcr.io/bioconductor/bioconductor_docker:devel + rspm: ~ + - os: macOS-latest + bioc: release + r: auto + cont: ~ + rspm: ~ + - os: windows-latest + bioc: release + r: auto + cont: ~ + rspm: ~ + steps: + - uses: neurogenomics/rworkflows@master + with: + run_bioccheck: ${{ false }} + run_rcmdcheck: ${{ true }} + as_cran: ${{ true }} + run_vignettes: ${{ true }} + has_testthat: ${{ true }} + run_covr: ${{ true }} + run_pkgdown: ${{ true }} + has_runit: ${{ false }} + has_latex: ${{ false }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run_docker: ${{ false }} + DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} + runner_os: ${{ runner.os }} + cache_version: cache-v1 + docker_registry: ghcr.io