From 83d313ca9b4846df00b8215a0ac8f5aaf85fb600 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Grelot?= <frederic.grelot@irstea.fr>
Date: Wed, 5 Jul 2023 17:45:00 +0200
Subject: [PATCH] =?UTF-8?q?Pr=C3=A9paration=20de=20la=20version=201.0.27.0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 dev/tag-message             | 16 ++++-----
 so.ii/DESCRIPTION           |  4 +--
 so.ii/NAMESPACE             |  2 ++
 so.ii/R/add_margin.R        | 65 +++++++++++++++++++++++++++++++++++++
 so.ii/R/aggregate_wide.R    | 52 +++++++++++++++++++++++++++++
 so.ii/man/add_margin.Rd     | 43 ++++++++++++++++++++++++
 so.ii/man/aggregate_wide.Rd | 37 +++++++++++++++++++++
 so.ii/man/kable_units.Rd    |  2 +-
 so.ii/man/map_so_ii.Rd      |  2 +-
 so.ii/man/plot_legend.Rd    |  2 +-
 10 files changed, 211 insertions(+), 14 deletions(-)
 create mode 100644 so.ii/R/add_margin.R
 create mode 100644 so.ii/R/aggregate_wide.R
 create mode 100644 so.ii/man/add_margin.Rd
 create mode 100644 so.ii/man/aggregate_wide.Rd

diff --git a/dev/tag-message b/dev/tag-message
index 01c6fcd..54af56c 100644
--- a/dev/tag-message
+++ b/dev/tag-message
@@ -1,18 +1,16 @@
-so.ii Version: 1.0.26.0
+so.ii Version: 1.0.27.0
 
 0 errors ✔ | 0 warnings ✔ | 0 notes ✔
 
 **Note de version**
-    * modification de map_so_ii
-    * nouvelle fonction interne calculate_terra_xy
+    * ajout de aggregate_wide
+    * ajout de add_margin
 
 **Détails**
-    * La librairie terra a changé sa façon de faire la barre d'échelle avec
-    sbar à partir de la version 1.7, de façon incompatible avec l'usage interne.
-    Une nouvelle fonction non exportée calculate_terra_xy est créée pour ne plus
-    dépendre des fonctionnalités de terra::sbar qui posent problème, et ne
-    permettaient plus de faire un positionnement par mots clés.
+    * aggregate_wide permet de renvoyer directement une matrice quand un
+    aggregate est réalisé sur 2 dimensions.
+    * add_margin permet d'utiliser addmargins directement sur un data.frame
 
-# git tag -a v1.0.25.0 -F dev/tag-message
+# git tag -a v1.0.27.0 -F dev/tag-message
 # git push --tags
 
diff --git a/so.ii/DESCRIPTION b/so.ii/DESCRIPTION
index db2020b..cf42619 100644
--- a/so.ii/DESCRIPTION
+++ b/so.ii/DESCRIPTION
@@ -1,6 +1,6 @@
 Package: so.ii
 Title: Utilities very useful to share within so_ii team
-Version: 1.0.26.0
+Version: 1.0.27.0
 Authors@R:
     c(
         person(given = "Frédéric",
@@ -33,5 +33,5 @@ Suggests:
     rmarkdown,
     testthat
 Roxygen: list(markdown = TRUE)
-RoxygenNote: 7.2.2
+RoxygenNote: 7.2.3
 VignetteBuilder: knitr
diff --git a/so.ii/NAMESPACE b/so.ii/NAMESPACE
index d7b419e..437c8b8 100644
--- a/so.ii/NAMESPACE
+++ b/so.ii/NAMESPACE
@@ -1,6 +1,8 @@
 # Generated by roxygen2: do not edit by hand
 
 export(add_inset)
+export(add_margin)
+export(aggregate_wide)
 export(current_version)
 export(estimate_catnat_freq)
 export(format_presence)
diff --git a/so.ii/R/add_margin.R b/so.ii/R/add_margin.R
new file mode 100644
index 0000000..7c2de82
--- /dev/null
+++ b/so.ii/R/add_margin.R
@@ -0,0 +1,65 @@
+#' @title Replace addmargins with treatment for data.frame
+#' 
+#' @param x either a matrix, an array or a data.frame
+#' @param name vector, if x is a data.frame, gives the poistion of what should
+#' be considered as names (and so not pass to addmargins).
+#' @param output character, gives the type of output, either as.is or a
+#' data.frame.
+#' @param ... arguments that will be used for addmargins
+#'
+#' @return A table, array or data.frame with margins added.
+#'
+#' @export
+#'
+#' @encoding UTF-8
+#'
+#' @author Frédéric Grelot
+#' 
+#' @examples
+#'
+#' add_margin(head(iris), 5)
+#' add_margin(head(iris), 5, "data.frame")
+#' add_margin(head(iris), 5, FUN = list("total" = sum))
+#' 
+#' x = data.frame(
+#'     gender = sample(c("H", "F"), 20, replace = TRUE),
+#'     region = sample(c("east", "west", "south", "north"), 20, replace = TRUE),
+#'     wealth = round(runif(20) * 10000),
+#'     size = round(runif(20) * 50 + 150)
+#' )
+#' add_margin(head(x), 1:2, margin = 1, FUN = list(mean = mean))
+ 
+add_margin = function(
+    x,
+    name,
+    output = c("normal", "data.frame"),
+    ...
+) {
+    output = match.arg(output)
+
+    if (is.data.frame(x)) {
+        if (missing(name)) name = 1
+        if (is.character(name)) name = grep(name, names(x))
+        x_name = x[name]
+        if (length(name) > 0) x = x[-name]
+        x = structure(
+            as.matrix(x),
+            dimnames = list(
+                apply(as.matrix(x_name), 1, paste, collapse = "_"),
+                colnames(x)
+            )
+        )
+    }
+
+    if (!is.array(x) && ! is.table(x)) {
+        stop("x should be something addmargins will expect at this stage!")
+    }
+
+    result = stats::addmargins(x, ...)
+
+    if (output == "data.frame") {
+        result = cbind(name = rownames(result), as.data.frame(result))
+    }
+
+    return(result)
+}
\ No newline at end of file
diff --git a/so.ii/R/aggregate_wide.R b/so.ii/R/aggregate_wide.R
new file mode 100644
index 0000000..182761b
--- /dev/null
+++ b/so.ii/R/aggregate_wide.R
@@ -0,0 +1,52 @@
+#' @title A wrapper to aggregate that gives a wide view of results
+#' 
+#' @param x data.frame 
+#' @param what vector of length
+#' @param fun function
+#'
+#' @return A matrix of result
+#' @export
+#'
+#' @encoding UTF-8
+#'
+#' @author Frédéric Grelot
+#' 
+#' @examples
+#' x = data.frame(
+#'     gender = sample(c("H", "F"), 20, replace = TRUE),
+#'     region = sample(c("east", "west", "south", "north"), 20, replace = TRUE),
+#'     wealth = round(runif(20) * 10000),
+#'     size = round(runif(20) * 50 + 150)
+#' )
+#' aggregate_wide(x)
+#' aggregate_wide(x, c("region", "gender", "wealth"))
+#' aggregate_wide(x, c("region", "gender", "size"))
+#' aggregate_wide(x, c("region", "gender", "wealth"), mean)
+
+aggregate_wide = function(x, what, fun = sum) {
+    if (missing(what)) what = 1:3
+    if (!is.vector(what) && length(what) == 3) {
+        stop("what should be a vector of length 3")
+    }
+
+    result = stats::aggregate(
+        x[what[3]],
+        x[c(what[1], what[2])],
+        fun,
+        drop = FALSE,
+        na.rm = TRUE
+    )
+    result = stats::reshape(
+        result,
+        direction = "wide",
+        idvar = names(result)[1],
+        timevar = names(result)[2]
+    )
+    result = structure(
+        as.matrix(result[-1]),
+        dimnames = list(
+            result[[1]],
+            gsub("^.*[.]", "", names(result)[-1]))
+    )
+    return(result)
+}
diff --git a/so.ii/man/add_margin.Rd b/so.ii/man/add_margin.Rd
new file mode 100644
index 0000000..4a8c762
--- /dev/null
+++ b/so.ii/man/add_margin.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/add_margin.R
+\encoding{UTF-8}
+\name{add_margin}
+\alias{add_margin}
+\title{Replace addmargins with treatment for data.frame}
+\usage{
+add_margin(x, name, output = c("normal", "data.frame"), ...)
+}
+\arguments{
+\item{x}{either a matrix, an array or a data.frame}
+
+\item{name}{vector, if x is a data.frame, gives the poistion of what should
+be considered as names (and so not pass to addmargins).}
+
+\item{output}{character, gives the type of output, either as.is or a
+data.frame.}
+
+\item{...}{arguments that will be used for addmargins}
+}
+\value{
+A table, array or data.frame with margins added.
+}
+\description{
+Replace addmargins with treatment for data.frame
+}
+\examples{
+
+add_margin(head(iris), 5)
+add_margin(head(iris), 5, "data.frame")
+add_margin(head(iris), 5, FUN = list("total" = sum))
+
+x = data.frame(
+    gender = sample(c("H", "F"), 20, replace = TRUE),
+    region = sample(c("east", "west", "south", "north"), 20, replace = TRUE),
+    wealth = round(runif(20) * 10000),
+    size = round(runif(20) * 50 + 150)
+)
+add_margin(head(x), 1:2, margin = 1, FUN = list(mean = mean))
+}
+\author{
+Frédéric Grelot
+}
diff --git a/so.ii/man/aggregate_wide.Rd b/so.ii/man/aggregate_wide.Rd
new file mode 100644
index 0000000..0466048
--- /dev/null
+++ b/so.ii/man/aggregate_wide.Rd
@@ -0,0 +1,37 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/aggregate_wide.R
+\encoding{UTF-8}
+\name{aggregate_wide}
+\alias{aggregate_wide}
+\title{A wrapper to aggregate that gives a wide view of results}
+\usage{
+aggregate_wide(x, what, fun = sum)
+}
+\arguments{
+\item{x}{data.frame}
+
+\item{what}{vector of length}
+
+\item{fun}{function}
+}
+\value{
+A matrix of result
+}
+\description{
+A wrapper to aggregate that gives a wide view of results
+}
+\examples{
+x = data.frame(
+    gender = sample(c("H", "F"), 20, replace = TRUE),
+    region = sample(c("east", "west", "south", "north"), 20, replace = TRUE),
+    wealth = round(runif(20) * 10000),
+    size = round(runif(20) * 50 + 150)
+)
+aggregate_wide(x)
+aggregate_wide(x, c("region", "gender", "wealth"))
+aggregate_wide(x, c("region", "gender", "size"))
+aggregate_wide(x, c("region", "gender", "wealth"), mean)
+}
+\author{
+Frédéric Grelot
+}
diff --git a/so.ii/man/kable_units.Rd b/so.ii/man/kable_units.Rd
index 8471709..91a5f5f 100644
--- a/so.ii/man/kable_units.Rd
+++ b/so.ii/man/kable_units.Rd
@@ -1,5 +1,5 @@
 % Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/kable_units.r
+% Please edit documentation in R/kable_units.R
 \encoding{UTF-8}
 \name{kable_units}
 \alias{kable_units}
diff --git a/so.ii/man/map_so_ii.Rd b/so.ii/man/map_so_ii.Rd
index b7e4a85..3db0d77 100644
--- a/so.ii/man/map_so_ii.Rd
+++ b/so.ii/man/map_so_ii.Rd
@@ -1,5 +1,5 @@
 % Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/map_so_ii.r
+% Please edit documentation in R/map_so_ii.R
 \encoding{UTF-8}
 \name{map_so_ii}
 \alias{map_so_ii}
diff --git a/so.ii/man/plot_legend.Rd b/so.ii/man/plot_legend.Rd
index ea96e6e..2edf131 100644
--- a/so.ii/man/plot_legend.Rd
+++ b/so.ii/man/plot_legend.Rd
@@ -1,5 +1,5 @@
 % Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/plot_legend.r
+% Please edit documentation in R/plot_legend.R
 \encoding{UTF-8}
 \name{plot_legend}
 \alias{plot_legend}
-- 
GitLab