From 895e4163a517ecbf2abac3804668b5f949d9ed0a Mon Sep 17 00:00:00 2001 From: Duncan Kennedy Date: Thu, 15 Aug 2024 15:55:01 -0600 Subject: [PATCH 01/10] `duplicates()` now preserves groups and attributes for "regular" and "sf" data frames --- R/duplicates.R | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/R/duplicates.R b/R/duplicates.R index bba1d15..d479ffb 100644 --- a/R/duplicates.R +++ b/R/duplicates.R @@ -27,6 +27,7 @@ duplicates <- function(.data, ..., .keep_all = TRUE) { col_names <- vapply(col, rlang::as_string, character(1)) } col_names <- unique(col_names) + chk_vector(col_names) check_values(col_names, "") check_names(.data, col_names) @@ -34,13 +35,43 @@ duplicates <- function(.data, ..., .keep_all = TRUE) { if (!length(col_names)) { return(.data) } + + grouped <- dplyr::is_grouped_df(.data) + groups <- dplyr::group_vars(.data) + groups_sym <- rlang::syms(groups) + .data_dup <- dplyr::select(.data, dplyr::all_of(col_names)) .data_dup <- .data_dup[duplicated(.data_dup), , drop = FALSE] .data_dup <- unique(.data_dup) - .data <- dplyr::inner_join(.data, .data_dup, by = col_names) + + is_sf = any(class(.data) == "sf") + if(is_sf) + { + .data <- poisspatial::ps_sfc_to_coords(.data) + .data_dup <- poisspatial::ps_sfc_to_coords(.data_dup) + if (any(col_names == "geometry")) { + col_names <- col_names[col_names != "geometry"] + col_names <- c(col_names, "X", "Y") + } + } + + .data <- dplyr::inner_join(.data, .data_dup, by = col_names) if (!(.keep_all)) { .data <- dplyr::select(.data, dplyr::all_of(col_names)) } + + if(is_sf) { + .data <- poisspatial::ps_coords_to_sfc(.data) + } + .data <- dplyr::as_tibble(.data) + + if(is_sf) { + .data <- poisspatial::ps_activate_sfc(.data) + } + + if (grouped) { + .data <- dplyr::group_by(.data, !!!groups_sym) + } .data } From 83d281ca5e357f3ace2be38d9a149837d58cac9b Mon Sep 17 00:00:00 2001 From: Duncan Kennedy Date: Fri, 16 Aug 2024 15:52:52 -0600 Subject: [PATCH 02/10] simplified dealing with sf tables with `duplicates()` --- R/duplicates.R | 47 ++++++++++------------------------------------- 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/R/duplicates.R b/R/duplicates.R index d479ffb..490b58d 100644 --- a/R/duplicates.R +++ b/R/duplicates.R @@ -21,57 +21,30 @@ duplicates <- function(.data, ..., .keep_all = TRUE) { chk_flag(.keep_all) col <- rlang::ensyms(...) - if (length(col) == 0) { - col_names <- colnames(.data) - } else { - col_names <- vapply(col, rlang::as_string, character(1)) - } + if (length(col) == 0) { col_names <- colnames(.data) } + else { col_names <- vapply(col, rlang::as_string, character(1)) } col_names <- unique(col_names) - chk_vector(col_names) check_values(col_names, "") check_names(.data, col_names) - if (!length(col_names)) { - return(.data) - } + if (!length(col_names)) { return(.data) } grouped <- dplyr::is_grouped_df(.data) groups <- dplyr::group_vars(.data) groups_sym <- rlang::syms(groups) + is_sf = any(class(.data) == "sf") + + .data <- tibble::as_tibble(.data) + .data_dup <- dplyr::select(.data, dplyr::all_of(col_names)) .data_dup <- .data_dup[duplicated(.data_dup), , drop = FALSE] .data_dup <- unique(.data_dup) - is_sf = any(class(.data) == "sf") - if(is_sf) - { - .data <- poisspatial::ps_sfc_to_coords(.data) - .data_dup <- poisspatial::ps_sfc_to_coords(.data_dup) - if (any(col_names == "geometry")) { - col_names <- col_names[col_names != "geometry"] - col_names <- c(col_names, "X", "Y") - } - } - .data <- dplyr::inner_join(.data, .data_dup, by = col_names) - if (!(.keep_all)) { - .data <- dplyr::select(.data, dplyr::all_of(col_names)) - } - - if(is_sf) { - .data <- poisspatial::ps_coords_to_sfc(.data) - } - - .data <- dplyr::as_tibble(.data) - - if(is_sf) { - .data <- poisspatial::ps_activate_sfc(.data) - } - - if (grouped) { - .data <- dplyr::group_by(.data, !!!groups_sym) - } + if (!(.keep_all)) { .data <- dplyr::select(.data, dplyr::all_of(col_names)) } + if (grouped) { .data <- dplyr::group_by(.data, !!!groups_sym) } + if (is_sf) { .data <- poisspatial::ps_activate_sfc(.data) } .data } From 3979a673a500f011bc8f152fc1f7f6389a3529b8 Mon Sep 17 00:00:00 2001 From: Duncan Kennedy Date: Tue, 20 Aug 2024 00:04:13 -0600 Subject: [PATCH 03/10] formatting --- R/duplicates.R | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/R/duplicates.R b/R/duplicates.R index 490b58d..7512b96 100644 --- a/R/duplicates.R +++ b/R/duplicates.R @@ -21,20 +21,25 @@ duplicates <- function(.data, ..., .keep_all = TRUE) { chk_flag(.keep_all) col <- rlang::ensyms(...) - if (length(col) == 0) { col_names <- colnames(.data) } - else { col_names <- vapply(col, rlang::as_string, character(1)) } + if (length(col) == 0) { + col_names <- colnames(.data) + } else { + col_names <- vapply(col, rlang::as_string, character(1)) + } col_names <- unique(col_names) chk_vector(col_names) check_values(col_names, "") check_names(.data, col_names) - if (!length(col_names)) { return(.data) } + if (!length(col_names)) { + return(.data) + } grouped <- dplyr::is_grouped_df(.data) groups <- dplyr::group_vars(.data) groups_sym <- rlang::syms(groups) - is_sf = any(class(.data) == "sf") + is_sf <- any(class(.data) == "sf") .data <- tibble::as_tibble(.data) @@ -43,8 +48,14 @@ duplicates <- function(.data, ..., .keep_all = TRUE) { .data_dup <- unique(.data_dup) .data <- dplyr::inner_join(.data, .data_dup, by = col_names) - if (!(.keep_all)) { .data <- dplyr::select(.data, dplyr::all_of(col_names)) } - if (grouped) { .data <- dplyr::group_by(.data, !!!groups_sym) } - if (is_sf) { .data <- poisspatial::ps_activate_sfc(.data) } + if (!(.keep_all)) { + .data <- dplyr::select(.data, dplyr::all_of(col_names)) + } + if (grouped) { + .data <- dplyr::group_by(.data, !!!groups_sym) + } + if (is_sf) { + .data <- poisspatial::ps_activate_sfc(.data) + } .data } From ef916b8f2135b6a1d96912aa0fb40c063d060ab1 Mon Sep 17 00:00:00 2001 From: Duncan Kennedy Date: Tue, 20 Aug 2024 00:22:09 -0600 Subject: [PATCH 04/10] `duplicates()` now works on any sf data frame regardless of sf column name --- R/duplicates.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/duplicates.R b/R/duplicates.R index 7512b96..cb53af8 100644 --- a/R/duplicates.R +++ b/R/duplicates.R @@ -40,6 +40,9 @@ duplicates <- function(.data, ..., .keep_all = TRUE) { groups_sym <- rlang::syms(groups) is_sf <- any(class(.data) == "sf") + if (is_sf) { + col_name_sf <- attributes(.data)$sf_column + } .data <- tibble::as_tibble(.data) @@ -55,7 +58,7 @@ duplicates <- function(.data, ..., .keep_all = TRUE) { .data <- dplyr::group_by(.data, !!!groups_sym) } if (is_sf) { - .data <- poisspatial::ps_activate_sfc(.data) + .data <- poisspatial::ps_activate_sfc(.data, sfc_name = col_name_sf) } .data } From c3c0d5044b5731ffda343c3684d22314d9e99415 Mon Sep 17 00:00:00 2001 From: Joe Thorley Date: Tue, 20 Aug 2024 07:31:16 -0700 Subject: [PATCH 05/10] added test that preserves single active geometry column called geometry --- tests/testthat/test-duplicates.R | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/testthat/test-duplicates.R b/tests/testthat/test-duplicates.R index 5727bd2..94b770e 100644 --- a/tests/testthat/test-duplicates.R +++ b/tests/testthat/test-duplicates.R @@ -106,3 +106,9 @@ test_that("errors when input argument is not a data.frame", { expect_error(duplicates(NULL), "Data.frame must be a data.frame.") expect_error(duplicates(NA), "Data.frame must be a data.frame.") }) + +test_that("preserves single active geometry column called geometry", { + skip_if_not_installed("sf") + data <- sf::st_sf(a=3, geometry = sf::st_sfc(sf::st_point(1:2))) + expect_identical(data, duplicates(data)) +}) From ea1450ac97aa786fb75de995a50ffa310eba56a6 Mon Sep 17 00:00:00 2001 From: Duncan Kennedy Date: Tue, 20 Aug 2024 11:32:42 -0600 Subject: [PATCH 06/10] `duplicates()` tests for grouped data frames and sf columns --- tests/testthat/test-duplicates.R | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/testthat/test-duplicates.R b/tests/testthat/test-duplicates.R index 94b770e..9d1469e 100644 --- a/tests/testthat/test-duplicates.R +++ b/tests/testthat/test-duplicates.R @@ -109,6 +109,37 @@ test_that("errors when input argument is not a data.frame", { test_that("preserves single active geometry column called geometry", { skip_if_not_installed("sf") + skip_if_not_installed("poisspatial") data <- sf::st_sf(a=3, geometry = sf::st_sfc(sf::st_point(1:2))) + data <- data[rep(1, 2), ] + rownames(data) <- NULL + data <- tibble::as_tibble(data) + data <- poisspatial::ps_activate_sfc(data) expect_identical(data, duplicates(data)) }) + +test_that("preserves groups and single active geometry column called earth", { + skip_if_not_installed("dplyr") + skip_if_not_installed("sf") + skip_if_not_installed("poisspatial") + + data <- data.frame( + X = c(1, 2, 2, 3, 3, 4, 4), + Y = c(11, 12, 13, 14, 14, 15, 15), + a = c("red", "orange", "yellow", "green", "green", "blue", "blue"), + b = c("white", "white", "white", "white", "white", "white", "white") + ) + data <- dplyr::group_by(data, a, b) + data <- poisspatial::ps_coords_to_sfc(data, sfc_name = "earth") + + data_dup <- data.frame( + X = c(3, 3, 4, 4), + Y = c(14, 14, 15, 15), + a = c("green", "green", "blue", "blue"), + b = c("white", "white", "white", "white") + ) + data_dup <- dplyr::group_by(data_dup, a, b) + data_dup <- poisspatial::ps_coords_to_sfc(data_dup, sfc_name = "earth") + + expect_identical(data_dup, duplicates(data)) +}) \ No newline at end of file From f831367083225f987256a64212cfbfed0a541d80 Mon Sep 17 00:00:00 2001 From: Duncan Kennedy Date: Tue, 20 Aug 2024 14:29:33 -0600 Subject: [PATCH 07/10] removed poisspatial dependency and split `duplicates()` tests for groups and sf data frames --- R/duplicates.R | 2 +- tests/testthat/test-duplicates.R | 75 ++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/R/duplicates.R b/R/duplicates.R index cb53af8..bd6c73a 100644 --- a/R/duplicates.R +++ b/R/duplicates.R @@ -58,7 +58,7 @@ duplicates <- function(.data, ..., .keep_all = TRUE) { .data <- dplyr::group_by(.data, !!!groups_sym) } if (is_sf) { - .data <- poisspatial::ps_activate_sfc(.data, sfc_name = col_name_sf) + .data <- sf::st_as_sf(.data, sf_column_name = col_name_sf) } .data } diff --git a/tests/testthat/test-duplicates.R b/tests/testthat/test-duplicates.R index 9d1469e..3d84ed5 100644 --- a/tests/testthat/test-duplicates.R +++ b/tests/testthat/test-duplicates.R @@ -1,13 +1,11 @@ test_that("returns only duplicated rows of selected columns", { - tib <- dplyr::tibble(x = c(1, 2, 1), y = c(1, 1, 1)) + tib <- tibble::tibble(x = c(1, 2, 1), y = c(1, 1, 1)) expect_identical(duplicates(tib), tib[c(1, 3), ]) expect_identical(duplicates(as.data.frame(tib)), tib[c(1, 3), ]) - expect_identical( duplicates(data.frame(x = c(1, 2, 1), y = 1:3), x), dplyr::tibble(x = c(1, 1), y = c(1L, 3L)) ) - expect_identical( duplicates(data.frame(x = c(1, 2, 1), y = 1:3), x, y), dplyr::tibble(x = double(0), y = integer(0)) @@ -40,18 +38,15 @@ test_that("keep_all working", { test_that("handles data frame with no rows", { - data <- dplyr::tibble(x = integer(), y = integer()) - + data <- tibble::tibble(x = integer(), y = integer()) expect_equal( duplicates(data), data ) - expect_equal( duplicates(data, x), data ) - expect_equal( duplicates(data, x, .keep_all = FALSE), dplyr::tibble(x = integer()) @@ -59,13 +54,11 @@ test_that("handles data frame with no rows", { }) test_that("handles data frame with no columns", { - data <- dplyr::tibble() - + data <- tibble::tibble() expect_identical( duplicates(data), data ) - expect_identical( duplicates(data, .keep_all = FALSE), data @@ -74,17 +67,14 @@ test_that("handles data frame with no columns", { test_that("handles columns with missing values", { data <- tibble::tibble(x = c(1, 2, NA, 1, 1), y = c(1, 1, NA, NA, NA)) - expect_identical( duplicates(data), tibble::tibble(x = c(1, 1), y = as.double(c(NA, NA))) ) - expect_identical( duplicates(data, y), data ) - expect_identical( duplicates(data, y, .keep_all = FALSE), tibble::tibble(y = c(1, 1, NA, NA, NA)) @@ -107,39 +97,66 @@ test_that("errors when input argument is not a data.frame", { expect_error(duplicates(NA), "Data.frame must be a data.frame.") }) +test_that("preserves groups", { + data <- tibble::tibble( + X = c(1, 2, 2, 3, 3, 4, 4), + Y = c(11, 12, 13, 14, 14, 15, 15), + a = c("red", "orange", "yellow", "green", "green", "blue", "blue"), + b = c("white", "white", "white", "white", "white", "white", "white") + ) + data <- dplyr::group_by(data, a, b) + + data_dup <- tibble::tibble( + X = c(3, 3, 4, 4), + Y = c(14, 14, 15, 15), + a = c("green", "green", "blue", "blue"), + b = c("white", "white", "white", "white") + ) + data_dup <- dplyr::group_by(data_dup, a, b) + + expect_identical(data_dup, duplicates(data)) +}) + test_that("preserves single active geometry column called geometry", { skip_if_not_installed("sf") - skip_if_not_installed("poisspatial") - data <- sf::st_sf(a=3, geometry = sf::st_sfc(sf::st_point(1:2))) - data <- data[rep(1, 2), ] - rownames(data) <- NULL - data <- tibble::as_tibble(data) - data <- poisspatial::ps_activate_sfc(data) - expect_identical(data, duplicates(data)) + + data <- tibble::tibble( + X = c(1, 2, 2, 3, 3, 4, 4), + Y = c(11, 12, 13, 14, 14, 15, 15), + a = c("red", "orange", "yellow", "green", "green", "blue", "blue"), + b = c("white", "white", "white", "white", "white", "white", "white") + ) + data <- sf::st_as_sf(data, coords = c("X", "Y")) + + data_dup <- tibble::tibble( + X = c(3, 3, 4, 4), + Y = c(14, 14, 15, 15), + a = c("green", "green", "blue", "blue"), + b = c("white", "white", "white", "white") + ) + data_dup <- sf::st_as_sf(data_dup, coords = c("X", "Y")) + + expect_identical(data_dup, duplicates(data)) }) -test_that("preserves groups and single active geometry column called earth", { - skip_if_not_installed("dplyr") +test_that("preserves single active geometry column called map", { skip_if_not_installed("sf") - skip_if_not_installed("poisspatial") - data <- data.frame( + data <- tibble::tibble( X = c(1, 2, 2, 3, 3, 4, 4), Y = c(11, 12, 13, 14, 14, 15, 15), a = c("red", "orange", "yellow", "green", "green", "blue", "blue"), b = c("white", "white", "white", "white", "white", "white", "white") ) - data <- dplyr::group_by(data, a, b) - data <- poisspatial::ps_coords_to_sfc(data, sfc_name = "earth") + data <- sf::st_as_sf(data, coords = c("X", "Y"), sf_column_name = "map") - data_dup <- data.frame( + data_dup <- tibble::tibble( X = c(3, 3, 4, 4), Y = c(14, 14, 15, 15), a = c("green", "green", "blue", "blue"), b = c("white", "white", "white", "white") ) - data_dup <- dplyr::group_by(data_dup, a, b) - data_dup <- poisspatial::ps_coords_to_sfc(data_dup, sfc_name = "earth") + data_dup <- sf::st_as_sf(data_dup, coords = c("X", "Y"), sf_column_name = "map") expect_identical(data_dup, duplicates(data)) }) \ No newline at end of file From 11f62c739d2b0e2ed3f203357f4d9f2abf8528d9 Mon Sep 17 00:00:00 2001 From: Duncan Kennedy Date: Sun, 8 Sep 2024 16:06:18 -0600 Subject: [PATCH 08/10] added `duplicates()` test for one active and one inactive geometry column --- tests/testthat/test-duplicates.R | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test-duplicates.R b/tests/testthat/test-duplicates.R index 3d84ed5..8c0b549 100644 --- a/tests/testthat/test-duplicates.R +++ b/tests/testthat/test-duplicates.R @@ -159,4 +159,34 @@ test_that("preserves single active geometry column called map", { data_dup <- sf::st_as_sf(data_dup, coords = c("X", "Y"), sf_column_name = "map") expect_identical(data_dup, duplicates(data)) -}) \ No newline at end of file +}) + +test_that("deals with one active geometry column and one inactive geometry column", { + skip_if_not_installed("sf") + + data <- tibble::tibble( + X = c(1, 2, 2, 3, 3, 4, 4), + Y = c(11, 12, 13, 14, 14, 15, 15), + a = c("red", "orange", "yellow", "green", "green", "blue", "blue"), + b = c("white", "white", "white", "white", "white", "white", "white"), + I = c(101, 102, 102, 103, 103, 104, 104), + J = c(1001, 1002, 1003, 1004, 1004, 1005, 1005) + ) + data <- sf::st_as_sf(data, coords = c("X", "Y")) + data <- tibble::as_tibble(data) + data <- sf::st_as_sf(data, coords = c("I", "J"), sf_column_name = "map") + + data_dup <- tibble::tibble( + X = c(3, 3, 4, 4), + Y = c(14, 14, 15, 15), + a = c("green", "green", "blue", "blue"), + b = c("white", "white", "white", "white"), + I = c(103, 103, 104, 104), + J = c(1004, 1004, 1005, 1005) + ) + data_dup <- sf::st_as_sf(data_dup, coords = c("X", "Y")) + data_dup <- tibble::as_tibble(data_dup) + data_dup <- sf::st_as_sf(data_dup, coords = c("I", "J"), sf_column_name = "map") + + expect_identical(data_dup, duplicates(data)) +}) From 3072d05552e8ea6f68cc2cd1338c2ce35eeb21e0 Mon Sep 17 00:00:00 2001 From: Duncan Kennedy Date: Mon, 9 Sep 2024 13:34:07 -0600 Subject: [PATCH 09/10] minor edits to `duplicates()` tests --- tests/testthat/test-duplicates.R | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/testthat/test-duplicates.R b/tests/testthat/test-duplicates.R index 8c0b549..6849df6 100644 --- a/tests/testthat/test-duplicates.R +++ b/tests/testthat/test-duplicates.R @@ -105,6 +105,7 @@ test_that("preserves groups", { b = c("white", "white", "white", "white", "white", "white", "white") ) data <- dplyr::group_by(data, a, b) + data <- duplicates(data) data_dup <- tibble::tibble( X = c(3, 3, 4, 4), @@ -114,7 +115,7 @@ test_that("preserves groups", { ) data_dup <- dplyr::group_by(data_dup, a, b) - expect_identical(data_dup, duplicates(data)) + expect_identical(data_dup, data) }) test_that("preserves single active geometry column called geometry", { @@ -127,6 +128,7 @@ test_that("preserves single active geometry column called geometry", { b = c("white", "white", "white", "white", "white", "white", "white") ) data <- sf::st_as_sf(data, coords = c("X", "Y")) + data <- duplicates(data) data_dup <- tibble::tibble( X = c(3, 3, 4, 4), @@ -136,7 +138,7 @@ test_that("preserves single active geometry column called geometry", { ) data_dup <- sf::st_as_sf(data_dup, coords = c("X", "Y")) - expect_identical(data_dup, duplicates(data)) + expect_identical(data_dup, data) }) test_that("preserves single active geometry column called map", { @@ -149,6 +151,7 @@ test_that("preserves single active geometry column called map", { b = c("white", "white", "white", "white", "white", "white", "white") ) data <- sf::st_as_sf(data, coords = c("X", "Y"), sf_column_name = "map") + data <- duplicates(data) data_dup <- tibble::tibble( X = c(3, 3, 4, 4), @@ -158,7 +161,7 @@ test_that("preserves single active geometry column called map", { ) data_dup <- sf::st_as_sf(data_dup, coords = c("X", "Y"), sf_column_name = "map") - expect_identical(data_dup, duplicates(data)) + expect_identical(data_dup, data) }) test_that("deals with one active geometry column and one inactive geometry column", { @@ -175,6 +178,7 @@ test_that("deals with one active geometry column and one inactive geometry colum data <- sf::st_as_sf(data, coords = c("X", "Y")) data <- tibble::as_tibble(data) data <- sf::st_as_sf(data, coords = c("I", "J"), sf_column_name = "map") + data <- duplicates(data) data_dup <- tibble::tibble( X = c(3, 3, 4, 4), @@ -188,5 +192,5 @@ test_that("deals with one active geometry column and one inactive geometry colum data_dup <- tibble::as_tibble(data_dup) data_dup <- sf::st_as_sf(data_dup, coords = c("I", "J"), sf_column_name = "map") - expect_identical(data_dup, duplicates(data)) + expect_identical(data_dup, data) }) From b46dbe286c0986a67e1f1504f61d4e81b9b151b6 Mon Sep 17 00:00:00 2001 From: Duncan Kennedy Date: Tue, 10 Sep 2024 18:28:49 -0600 Subject: [PATCH 10/10] Bump version to 0.1.0.9000 --- DESCRIPTION | 2 +- NEWS.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 8e83905..76c3f12 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: tidyplus Title: Additional 'tidyverse' Functions -Version: 0.1.0 +Version: 0.1.0.9000 Authors@R: c( person("Joe", "Thorley", , "joe@poissonconsulting.ca", role = "aut", comment = c(ORCID = "0000-0002-7683-4592")), diff --git a/NEWS.md b/NEWS.md index d16e233..8a60221 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,10 @@ +# tidyplus 0.1.0.9000 + +- `duplicates()` now preserves groups and attributes for "regular" and "sf" data frames. +- Added tests for `duplicates()`. + # tidyplus 0.1.0 - Added the `str_replace_vec()` function.