From b9411070857f24deb6ce48df178ef5cc9aac2aa5 Mon Sep 17 00:00:00 2001 From: vbonhomme Date: Fri, 27 Nov 2015 16:51:14 +0100 Subject: [PATCH] part of #13 and #106 --- DESCRIPTION | 79 +-- Momocs.Rproj | 2 +- NAMESPACE | 8 + R/babel-bridges.R | 44 +- R/cl-def-CooCoe.R | 10 +- R/cl-def-Opn.R | 36 +- R/cl-utilities.R | 33 +- R/coo-utilities.R | 1 + R/core-ldk-procrustes.R | 18 +- R/gr-Coo.R | 20 +- man/a2l.Rd | 14 +- man/a2m.Rd | 14 +- man/as_df.Rd | 14 +- man/chc2Out.Rd | 6 +- man/chc2pix.Rd | 6 +- man/fgProcrustes.Rd | 3 + man/get_cur_binded.Rd | 5 +- man/get_curcoo_binded.Rd | 22 + man/import_StereoMorph.Rd | 28 +- man/import_jpg.Rd | 9 +- man/import_tps.Rd | 9 +- man/l2a.Rd | 14 +- man/l2m.Rd | 9 +- man/m2a.Rd | 9 +- man/m2d.Rd | 9 +- man/m2l.Rd | 9 +- man/m2ll.Rd | 28 + man/nef2Coe.Rd | 7 +- man/ntsrow2Coo.Rd | 7 +- man/pProcrustes.Rd | 3 + man/pix2chc.Rd | 7 +- man/stack.Coo.Rd | 8 +- man/tie_jpg_txt.Rd | 7 +- man/tps2Coo.Rd | 7 +- vignettes/Momocs_speed_dating.R | 304 ---------- vignettes/Momocs_speed_dating.Rmd | 4 +- vignettes/Momocs_speed_dating.html | 919 ----------------------------- 37 files changed, 293 insertions(+), 1439 deletions(-) create mode 100644 man/get_curcoo_binded.Rd create mode 100644 man/m2ll.Rd delete mode 100644 vignettes/Momocs_speed_dating.R delete mode 100644 vignettes/Momocs_speed_dating.html diff --git a/DESCRIPTION b/DESCRIPTION index 40941735..793c6ff0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,47 +1,54 @@ Package: Momocs Title: Morphometrics using R -Version: 0.9.57 -Date: 2015-11-26 +Version: 0.9.58 +Date: 2015-11-27 Authors@R: c( person("Vincent", "Bonhomme", , - "bonhomme.vincent@gmail.com", c("aut", "cre")), person("Julien", - "Claude", , , c("aut")) ) -Description: Aiming to provide a complete and convenient toolkit for - morphometrics, Momocs is intended for scientists interested in - describing quantitatively the shape, and its variations, of the - objects they study. In the last decade, R has become the - open-source lingua franca for statistics, and morphometrics - known its so-called 'revolution'. Nevertheless, morphometric - analyses still have to be carried out using various software - packages, for which source code is mostly unavailable or - copyrighted. Moreover, existing software packages cannot be - extended and their bugs are hard to detect and thus correct. - This situation is detrimental to morphometrics; time is wasted, - analyses are restricted to available methods, and last but not - least, are poorly reproducible. This impedes collaborative - effort both in software development and in morphometric studies. - By gathering the common morphometric approaches in an - open-source environment and welcoming contributions, Momocs is - an (work-in-progress) attempt to solve this twofold problem and - to push morphometrics one step further. It hinges on the core - functions published in the book Morphometrics using R (Claude, - 2008), but has been further extended to allow other shape - description systems. So far, configurations of landmarks, - outlines and open outline analyses, along with some facilities - for traditional morphometrics have been implemented. Prior to - analysis, Momocs can be used to acquire and manipulate data or - to import/export from/to other formats. Momocs also has the - facility for a wide range of multivariate analyses and - production of the companion graphics. Thus a researcher will - find that just a few lines of code will provide initial results, - but the methods implemented can be finely tuned and extended - according to the user's needs. + "bonhomme.vincent@gmail.com", c("aut", "cre")), + person("Julien", "Claude", , , c("aut")) ) +Description: Aiming to provide a complete and convenient + toolkit for morphometrics, Momocs is intended for + scientists interested in describing quantitatively + the shape, and its variations, of the objects they + study. In the last decade, R has become the + open-source lingua franca for statistics, and + morphometrics known its so-called 'revolution'. + Nevertheless, morphometric analyses still have to be + carried out using various software packages, for + which source code is mostly unavailable or + copyrighted. Moreover, existing software packages + cannot be extended and their bugs are hard to detect + and thus correct. This situation is detrimental to + morphometrics; time is wasted, analyses are + restricted to available methods, and last but not + least, are poorly reproducible. This impedes + collaborative effort both in software development and + in morphometric studies. By gathering the common + morphometric approaches in an open-source environment + and welcoming contributions, Momocs is an + (work-in-progress) attempt to solve this twofold + problem and to push morphometrics one step further. + It hinges on the core functions published in the book + Morphometrics using R (Claude, 2008), but has been + further extended to allow other shape description + systems. So far, configurations of landmarks, + outlines and open outline analyses, along with some + facilities for traditional morphometrics have been + implemented. Prior to analysis, Momocs can be used to + acquire and manipulate data or to import/export + from/to other formats. Momocs also has the facility + for a wide range of multivariate analyses and + production of the companion graphics. Thus a + researcher will find that just a few lines of code + will provide initial results, but the methods + implemented can be finely tuned and extended + according to the user's needs. License: GPL-2 | GPL-3 URL: http://www.vincentbonhomme.fr/Momocs BugReports: https://github.com/vbonhomme/Momocs Depends: R(>= 3.1) LazyData: true -Imports: ape, dplyr, magrittr, graphics, geometry, ggplot2, jpeg, MASS, - plyr, reshape2, sp, utils +Imports: ape, dplyr, magrittr, graphics, geometry, ggplot2, + jpeg, MASS, plyr, reshape2, sp, utils Suggests: devtools, ggtree, knitr, rmarkdown VignetteBuilder: knitr RoxygenNote: 5.0.1 diff --git a/Momocs.Rproj b/Momocs.Rproj index e33841fd..a14289f8 100644 --- a/Momocs.Rproj +++ b/Momocs.Rproj @@ -18,4 +18,4 @@ StripTrailingWhitespace: Yes BuildType: Package PackageInstallArgs: --no-multiarch PackageCheckArgs: --as-cran -PackageRoxygenize: rd,collate,namespace,vignette +PackageRoxygenize: rd,collate,namespace diff --git a/NAMESPACE b/NAMESPACE index 3c02212d..a2d003d0 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -187,6 +187,8 @@ S3method(filter,PCA) S3method(filter,default) S3method(get_cur_binded,Coo) S3method(get_cur_binded,Ldk) +S3method(get_curcoo_binded,Ldk) +S3method(get_curcoo_binded,default) S3method(get_ldk,Ldk) S3method(get_ldk,Opn) S3method(get_ldk,Out) @@ -490,6 +492,7 @@ export(filter) export(get_chull_area) export(get_chull_volume) export(get_cur_binded) +export(get_curcoo_binded) export(get_ldk) export(get_pairs) export(harm_pow) @@ -515,6 +518,10 @@ export(is.OpnCoe) export(is.Out) export(is.OutCoe) export(is.PCA) +export(is.cur) +export(is.fac) +export(is.ldk) +export(is.links) export(is_closed) export(l2a) export(l2m) @@ -531,6 +538,7 @@ export(links_delaunay) export(m2a) export(m2d) export(m2l) +export(m2ll) export(measure) export(mshapes) export(mutate) diff --git a/R/babel-bridges.R b/R/babel-bridges.R index d23e5194..b355ce48 100644 --- a/R/babel-bridges.R +++ b/R/babel-bridges.R @@ -16,7 +16,7 @@ #' l #' m <- l2m(l) #' m -#' @family babel functions +#' @family bridges functions #' @export l2m <- function(l) { m <- cbind(l$x, l$y) @@ -24,7 +24,6 @@ l2m <- function(l) { return(m) } - #' Converts a list of coordinates to an array of coordinates #' #' l2a converts a list of \code{k} matrices with \code{m} rows @@ -36,14 +35,14 @@ l2m <- function(l) { #' @usage l2a(l) #' @param l \code{list} of matrices of the same dimension. #' @return an array of coordinates. -#' @seealso \link{a2l}. +#' @family bridges functions #' @examples #' data(wings) #' l <- wings$coo #' l #' a <- l2a(l) #' a -#' @family babel functions +#' @family bridges functions #' @export l2a <- function(l) { .check(length(unique(sapply(l, length))) == 1, @@ -73,7 +72,7 @@ l2a <- function(l) { #' l #' a <- l2a(l) #' a -#' @family babel functions +#' @family bridges functions #' @export a2l <- function(a) { .check(is.array(a) & length(dim(a)==3), @@ -101,7 +100,7 @@ a2l <- function(a) { #' data(wings) #' a <- l2a(wings$coo) #' a -#' @family babel functions +#' @family bridges functions #' @export a2m <- function(a) { # ugly @@ -130,7 +129,7 @@ a2m <- function(a) { #' data(wings) #' m <- a2m(l2a(wings$coo)) #' m2a(m) -#' @family babel functions +#' @family bridges functions #' @export m2a <- function(m) { # ugly @@ -153,7 +152,7 @@ m2a <- function(m) { #' @examples #' data(wings) #' m2d(wings[3]) -#' @family babel functions +#' @family bridges functions #' @export m2d <- function(m){ m <- coo_check(m) @@ -176,12 +175,37 @@ m2d <- function(m){ #' l #' m <- l2m(l) #' m -#' @family babel functions +#' @family bridges functions #' @export m2l <- function(m) { return(list(x = m[, 1], y = m[, 2])) } +#’ Converts a matrix of coordinates into a list of matrices +#' +#' Used internally to hanle coo and cur in \code{Ldk} objects but may be +#' useful elsewhere +#' @param m \code{matrix}, typically of (x; y) coordinates +#' @param index \code{numeric}, the number of coordinates for every slice. +#' @examples +#' m2ll(wings[1], c(6, 4, 3, 5)) +#' @family bridges functions +#' @export +m2ll <- function(m, index=NULL){ + # no slicing case, we return a matrix + if (is.null(index)) + return(m) + # slicing case, we slices + .check(sum(index)==nrow(m), + "nrow(m) and sum(index) must match") + start <- cumsum(c(1, index[-length(index)])) + end <- cumsum(index) + ll <- vector("list", length(start)) + for (i in seq_along(start)){ + ll[[i]] <- m[start[i]:end[i], ] + } + return(ll) +} # as_df -------------------------------- @@ -199,7 +223,7 @@ m2l <- function(m) { #' head(as_df(bot.p)) #' bot.l <- LDA(bot.p, "type") #' head(as_df(bot.l)) -#' @family babel functions +#' @family bridges functions #' @export as_df <- function(x){ UseMethod("as_df") diff --git a/R/cl-def-CooCoe.R b/R/cl-def-CooCoe.R index 9d62b015..96fda79c 100644 --- a/R/cl-def-CooCoe.R +++ b/R/cl-def-CooCoe.R @@ -423,9 +423,13 @@ names.Coe <- function(x) { } # component testers --------- -is.fac <- function(x) length(x$fac) > 0 -is.ldk <- function(x) length(x$ldk) > 0 -is.cur <- function(x) length(x$cur) > 0 +#' @export +is.fac <- function(x) length(x$fac) > 0 +#' @export +is.ldk <- function(x) length(x$ldk) > 0 +#' @export +is.cur <- function(x) length(x$cur) > 0 +#' @export is.links <- function(x) is.matrix(x$links) diff --git a/R/cl-def-Opn.R b/R/cl-def-Opn.R index 258ddaad..5b95f524 100644 --- a/R/cl-def-Opn.R +++ b/R/cl-def-Opn.R @@ -164,17 +164,17 @@ print.OpnCoe <- function(x, ...) { cat("An OpnCoe object [", met) cat(rep("-", 20), "\n", sep = "") coo_nb <- nrow(OpnCoe$coe) #nrow method ? + cat(" - $coe:", coo_nb, "open outlines described\n") if (combined) { degree <- ncol(OpnCoe$coe) # p==3 is the case for dfourier all along the method # if (p==3) degree <- degree/2 # number of outlines and harmonics - cat(" - $coe:", coo_nb, "open outlines described\n") -# if (p==3){ -# cat(degree, " harmonics\n", sep="") -# } else { -# cat(degree, "th degree (+Intercept)\n", sep="") -# } + # if (p==3){ + # cat(degree, " harmonics\n", sep="") + # } else { + # cat(degree, "th degree (+Intercept)\n", sep="") + # } # we print the baselines if (!is.null(c(x$baseline1, x$baseline2))) { cat(" - $baseline1: (", paste(x$baseline1, collapse="; "), ")\n", sep="") @@ -190,16 +190,20 @@ print.OpnCoe <- function(x, ...) { print(round(OpnCoe$coe[row.eg, col.eg], 3)) cat("etc.\n") } else { - cat(" - $baseline1, $baseline2: baselines registrations\n") - cat(" - $coe: coefficients\n")} -# if (p != 3) { -# # r2 quick summary -# r2 <- OpnCoe$r2 -# cat(" - $r2: min=", signif(min(r2), 3), -# ", median=", signif(median(r2), 3), -# ", mean=", signif(mean(r2), 3), -# ", sd=", signif(mean(r2), 3), -# ", max=", signif(max(r2), 3), "\n", sep="")} + # we print the baselines + if (!is.null(c(x$baseline1, x$baseline2))) { + cat(" - $baseline1: (", paste(x$baseline1, collapse="; "), "), ", sep="") + cat("$baseline2: (", paste(x$baseline2, collapse="; "), ")\n", sep="") + } + } + # if (p != 3) { + # # r2 quick summary + # r2 <- OpnCoe$r2 + # cat(" - $r2: min=", signif(min(r2), 3), + # ", median=", signif(median(r2), 3), + # ", mean=", signif(mean(r2), 3), + # ", sd=", signif(mean(r2), 3), + # ", max=", signif(max(r2), 3), "\n", sep="")} # we print the fac .print.fac(OpnCoe$fac) } diff --git a/R/cl-utilities.R b/R/cl-utilities.R index dc687632..29e2f40f 100644 --- a/R/cl-utilities.R +++ b/R/cl-utilities.R @@ -399,12 +399,13 @@ get_ldk.Out <- function(Coo) { #' @export get_ldk.Opn <- get_ldk.Out -#' Retrieves semi-landmarks coordinates from Ldk objects +#' Binds semi-landmarks coordinates from Ldk objects #' #' Binds groups (if any) of landmarks from the \code{$cur} #' on \link{Ldk} objects #' @param Ldk an \link{Ldk} object #' @return a list of matrices +#' @family get_cur functions #' @export get_cur_binded <- function(Ldk){ UseMethod("get_cur_binded") @@ -423,6 +424,36 @@ function(Ldk){ lapply(Ldk$cur, function(x) do.call(rbind, x)) } +#' Binds landmarks and semi-landmarks coordinates from Ldk objects +#' +#' Binds \code{$coo} with groups (if any) of landmarks from the \code{$cur} +#' on \link{Ldk} objects +#' @param Ldk an \link{Ldk} object +#' @family get_cur functions +#' @return a list of matrices +#' @export +get_curcoo_binded <- function(x){ + UseMethod("get_curcoo_binded") +} + +#' @export +get_curcoo_binded.default <- function(x){ + cat("* only defined on Ldk objects") +} + +#' @export +get_curcoo_binded.Ldk <- function(x){ + # if there are cur, we bind them after Coo + if (is.cur(x)){ + x$nb_cur <- c(nrow(x$coo[[1]]), sapply(x$cur[[1]], nrow)) + x$coo <- mapply("rbind", x$coo, get_cur_binded(x), SIMPLIFY=FALSE) + x$cur <- NULL + } + return(x) + # curve case. we bind +} + + # class testers ------------- #' Tests if an object is of a given class #' diff --git a/R/coo-utilities.R b/R/coo-utilities.R index aced53c6..28d5a57f 100644 --- a/R/coo-utilities.R +++ b/R/coo-utilities.R @@ -489,6 +489,7 @@ coo_trans.Coo <- function(coo, x = 0, y = 0) { return(Coo) } +# coo_slice------------------ #' Slices shapes between successive coordinates #' #' Takes a shape with n coordinates. When you pass this function with at least diff --git a/R/core-ldk-procrustes.R b/R/core-ldk-procrustes.R index 941c0440..73516ad6 100644 --- a/R/core-ldk-procrustes.R +++ b/R/core-ldk-procrustes.R @@ -1,5 +1,5 @@ -##### Core functions for Procrustes alignements +# fProcrustes----------------- # should DF be used for calibrate_deviations ? #todo #' Full Procrustes alignment between two shapes #' @@ -60,6 +60,7 @@ fProcrustes <- function(coo1, coo2) { #' } or an \link{Out}, \link{Opn} or an \link{Ldk} object. #' @note Slightly less optimized than procGPA in the shapes package (~20% on my machine). #' @references Claude, J. (2008). Morphometrics with R. Analysis (p. 316). Springer. +#' @family procrustes functions: #' @export fgProcrustes <- function(x, tol, verbose, coo) { UseMethod("fgProcrustes") @@ -141,7 +142,7 @@ fgProcrustes.Out <- function(x, tol = 1e-10, verbose = FALSE, coo=FALSE) { Coo <- x # if no $ldk defined, we convert Out into a Ldk and then # perform the fgProcrustes and return back an Out object. - if (coo | length(Coo$ldk) == 0) { + if (coo | (length(Coo$ldk) == 0)) { if (verbose) { if (coo){ cat (" * Using $coo, not $ldk.\n") @@ -203,8 +204,9 @@ fgProcrustes.Opn <- fgProcrustes.Out #' @export fgProcrustes.Ldk <- function(x, tol = 1e-10, verbose = FALSE, coo=NULL) { - Coo <- x - Coo2 <- Coo + if (is.cur(x)) + x %<>% get_curcoo_binded() + Coo2 <- Coo <- x ref <- l2a(Coo2$coo) tar <- fgProcrustes(ref, tol = tol, verbose = verbose)$rotated Coo2$coo <- a2l(tar) @@ -213,9 +215,16 @@ fgProcrustes.Ldk <- function(x, tol = 1e-10, verbose = FALSE, coo=NULL) { names(Coo2$coo) <- names(Coo$coo) class(Coo2) <- c("LdkCoe", "Coe", class(Coo2)) Coo2$cuts <- ncol(Coo2$coe) + #we reseperate coo and cur + if (is.cur(x)){ + coos <- lapply(Coo2$coo, m2ll, Coo2$nb_cur) + Coo2$coo <- lapply(coos, "[[", 1) + Coo2$cur <- lapply(coos, "[", -1) + } return(Coo2) } +# pProcrustes----------------- #' Partial Procrustes alignment between two shapes #' #' Directly borrowed from Claude (2008), and called \code{pPsup} there. @@ -230,6 +239,7 @@ fgProcrustes.Ldk <- function(x, tol = 1e-10, verbose = FALSE, coo=NULL) { #' \item \code{rho} trigonometric Procrustes distance. #' } #' @references Claude, J. (2008). Morphometrics with R. Analysis (p. 316). Springer. +#' @family procrustes functions: #' @export pProcrustes <- function(coo1, coo2) { # directly borrowed from Claude diff --git a/R/gr-Coo.R b/R/gr-Coo.R index 0b6cdb6e..0ed850bc 100644 --- a/R/gr-Coo.R +++ b/R/gr-Coo.R @@ -175,9 +175,9 @@ stack.OutCoe <- function(x, nb.pts=120, ...){ #' @rdname stack.Coo #' @export stack.Ldk <- function(x, cols, borders, first.point = TRUE, centroid = TRUE, - ldk = TRUE, ldk.pch = 3, ldk.col = "#333333", ldk.cex = 0.5, + ldk = TRUE, ldk.pch = 20, ldk.col=col_alpha("#000000", 0.3), ldk.cex = 0.3, ldk_links = FALSE, ldk_confell = FALSE, ldk_contour = FALSE, - ldk_chull = FALSE, ldk_labels = FALSE, cur=TRUE, cur.pch=".", xy.axis = TRUE, title=substitute(x), ...) { + ldk_chull = FALSE, ldk_labels = FALSE, cur=TRUE, cur_pch=20, xy.axis = TRUE, title=substitute(x), ...) { Coo <- x if (missing(cols)) { cols <- rep(NA, length(Coo)) @@ -193,26 +193,32 @@ stack.Ldk <- function(x, cols, borders, first.point = TRUE, centroid = TRUE, } op <- par(mar = c(3, 3, 2, 1)) on.exit(par(op)) - wdw <- apply(l2a(lapply(Coo$coo, - function(x) apply(x, 2, range))), 2, range) + if (is.cur(Coo)){ + wdw <- apply(l2a(lapply(get_curcoo_binded(Coo)$coo, function(x) apply(x, 2, range))), 2, range) + } else { + wdw <- apply(l2a(lapply(Coo$coo, function(x) apply(x, 2, range))), 2, range) + } plot(NA, xlim = wdw[, 1], ylim = wdw[, 2], asp = 1, las = 1, cex.axis = 2/3, ann = FALSE, frame = FALSE) title(title) if (xy.axis) { abline(h = 0, v = 0, col = "grey80", lty = 2) } + # semilandmarks lines if (cur | (is.cur(Coo) & missing(cur))){ for (i in 1:length(Coo)) { lapply(Coo$cur[[i]], lines, col=col_alpha("#000000", 0.95)) } } + # points for (i in 1:length(Coo)) { points(Coo$coo[[i]], pch = ldk.pch, col = ldk.col, cex = ldk.cex) } + # semilandmarks if (is.cur(Coo)){ cur_binded <- get_cur_binded(Coo) for (i in 1:length(Coo)) { - points(cur_binded[[i]], pch = cur.pch, col = ldk.col, cex = ldk.cex) + points(cur_binded[[i]], pch = cur_pch, col = ldk.col, cex = ldk.cex*0.25) } } # Specific to Ldk not very clean below #todo @@ -234,8 +240,8 @@ stack.Ldk <- function(x, cols, borders, first.point = TRUE, centroid = TRUE, if (ldk_labels) { ldk_labels(mshapes(A)) } - points(mA, pch = 20, - cex = ifelse(ldk.cex > 0.5, ldk.cex * 1.5, 1), col = "grey20") + points(mA, pch = 3, + cex = ifelse(ldk.cex > 0.5, ldk.cex * 1.5, 2), col = "grey50") } diff --git a/man/a2l.Rd b/man/a2l.Rd index f0e2e52b..dbd5d8eb 100644 --- a/man/a2l.Rd +++ b/man/a2l.Rd @@ -28,15 +28,9 @@ a <- l2a(l) a } \seealso{ -Other babel functions: \code{\link{a2m}}, - \code{\link{as_df}}, \code{\link{chc2Out}}, - \code{\link{chc2pix}}, - \code{\link{import_StereoMorph_curve1}}, - \code{\link{import_jpg}}, \code{\link{import_tps}}, - \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{m2l}}, - \code{\link{nef2Coe}}, \code{\link{ntsrow2Coo}}, - \code{\link{pix2chc}}, \code{\link{tie_jpg_txt}}, - \code{\link{tps2coo}} +Other bridges functions: \code{\link{a2m}}, + \code{\link{as_df}}, \code{\link{l2a}}, + \code{\link{l2m}}, \code{\link{m2a}}, \code{\link{m2d}}, + \code{\link{m2ll}}, \code{\link{m2l}} } diff --git a/man/a2m.Rd b/man/a2m.Rd index 1b9ced61..a6256e86 100644 --- a/man/a2m.Rd +++ b/man/a2m.Rd @@ -28,15 +28,9 @@ a \seealso{ \link{m2a} the reverse function. -Other babel functions: \code{\link{a2l}}, - \code{\link{as_df}}, \code{\link{chc2Out}}, - \code{\link{chc2pix}}, - \code{\link{import_StereoMorph_curve1}}, - \code{\link{import_jpg}}, \code{\link{import_tps}}, - \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{m2l}}, - \code{\link{nef2Coe}}, \code{\link{ntsrow2Coo}}, - \code{\link{pix2chc}}, \code{\link{tie_jpg_txt}}, - \code{\link{tps2coo}} +Other bridges functions: \code{\link{a2l}}, + \code{\link{as_df}}, \code{\link{l2a}}, + \code{\link{l2m}}, \code{\link{m2a}}, \code{\link{m2d}}, + \code{\link{m2ll}}, \code{\link{m2l}} } diff --git a/man/as_df.Rd b/man/as_df.Rd index ffb14175..0c0ecac3 100644 --- a/man/as_df.Rd +++ b/man/as_df.Rd @@ -26,15 +26,9 @@ bot.l <- LDA(bot.p, "type") head(as_df(bot.l)) } \seealso{ -Other babel functions: \code{\link{a2l}}, - \code{\link{a2m}}, \code{\link{chc2Out}}, - \code{\link{chc2pix}}, - \code{\link{import_StereoMorph_curve1}}, - \code{\link{import_jpg}}, \code{\link{import_tps}}, - \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{m2l}}, - \code{\link{nef2Coe}}, \code{\link{ntsrow2Coo}}, - \code{\link{pix2chc}}, \code{\link{tie_jpg_txt}}, - \code{\link{tps2coo}} +Other bridges functions: \code{\link{a2l}}, + \code{\link{a2m}}, \code{\link{l2a}}, \code{\link{l2m}}, + \code{\link{m2a}}, \code{\link{m2d}}, \code{\link{m2ll}}, + \code{\link{m2l}} } diff --git a/man/chc2Out.Rd b/man/chc2Out.Rd index 43786525..c53f19ec 100644 --- a/man/chc2Out.Rd +++ b/man/chc2Out.Rd @@ -58,13 +58,9 @@ Elliptic Fourier features of a closed contour. \seealso{ \link{pix2chc} -Other babel functions: \code{\link{a2l}}, - \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2pix}}, +Other babel functions: \code{\link{chc2pix}}, \code{\link{import_StereoMorph_curve1}}, \code{\link{import_jpg}}, \code{\link{import_tps}}, - \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{m2l}}, \code{\link{nef2Coe}}, \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} diff --git a/man/chc2pix.Rd b/man/chc2pix.Rd index 73c7f632..3c0d4cab 100644 --- a/man/chc2pix.Rd +++ b/man/chc2pix.Rd @@ -27,13 +27,9 @@ Elliptic Fourier features of a closed contour. \seealso{ \link{pix2chc}, \link{chc2Out} -Other babel functions: \code{\link{a2l}}, - \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, +Other babel functions: \code{\link{chc2Out}}, \code{\link{import_StereoMorph_curve1}}, \code{\link{import_jpg}}, \code{\link{import_tps}}, - \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{m2l}}, \code{\link{nef2Coe}}, \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} diff --git a/man/fgProcrustes.Rd b/man/fgProcrustes.Rd index 4e83a404..1afee861 100644 --- a/man/fgProcrustes.Rd +++ b/man/fgProcrustes.Rd @@ -43,4 +43,7 @@ Slightly less optimized than procGPA in the shapes package (~20% on my machine). \references{ Claude, J. (2008). Morphometrics with R. Analysis (p. 316). Springer. } +\seealso{ +Other procrustes functions:: \code{\link{pProcrustes}} +} diff --git a/man/get_cur_binded.Rd b/man/get_cur_binded.Rd index 178c416f..4a7df550 100644 --- a/man/get_cur_binded.Rd +++ b/man/get_cur_binded.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/cl-utilities.R \name{get_cur_binded} \alias{get_cur_binded} -\title{Retrieves semi-landmarks coordinates from Ldk objects} +\title{Binds semi-landmarks coordinates from Ldk objects} \usage{ get_cur_binded(Ldk) } @@ -16,4 +16,7 @@ a list of matrices Binds groups (if any) of landmarks from the \code{$cur} on \link{Ldk} objects } +\seealso{ +Other get_cur functions: \code{\link{get_curcoo_binded}} +} diff --git a/man/get_curcoo_binded.Rd b/man/get_curcoo_binded.Rd new file mode 100644 index 00000000..46b58687 --- /dev/null +++ b/man/get_curcoo_binded.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/cl-utilities.R +\name{get_curcoo_binded} +\alias{get_curcoo_binded} +\title{Binds landmarks and semi-landmarks coordinates from Ldk objects} +\usage{ +get_curcoo_binded(x) +} +\arguments{ +\item{Ldk}{an \link{Ldk} object} +} +\value{ +a list of matrices +} +\description{ +Binds \code{$coo} with groups (if any) of landmarks from the \code{$cur} +on \link{Ldk} objects +} +\seealso{ +Other get_cur functions: \code{\link{get_cur_binded}} +} + diff --git a/man/import_StereoMorph.Rd b/man/import_StereoMorph.Rd index f72f68cc..9e9dfcbf 100644 --- a/man/import_StereoMorph.Rd +++ b/man/import_StereoMorph.Rd @@ -31,24 +31,16 @@ of \link{Opn} or \link{Ldk} objects, respectively. Please do not hesitate to con should you have a particular case or need something. } \seealso{ -Other babel functions: \code{\link{a2l}}, - \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, - \code{\link{import_jpg}}, \code{\link{import_tps}}, - \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{m2l}}, - \code{\link{nef2Coe}}, \code{\link{ntsrow2Coo}}, - \code{\link{pix2chc}}, \code{\link{tie_jpg_txt}}, - \code{\link{tps2coo}} +Other babel functions: \code{\link{chc2Out}}, + \code{\link{chc2pix}}, \code{\link{import_jpg}}, + \code{\link{import_tps}}, \code{\link{nef2Coe}}, + \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, + \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} -Other babel functions: \code{\link{a2l}}, - \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, - \code{\link{import_jpg}}, \code{\link{import_tps}}, - \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{m2l}}, - \code{\link{nef2Coe}}, \code{\link{ntsrow2Coo}}, - \code{\link{pix2chc}}, \code{\link{tie_jpg_txt}}, - \code{\link{tps2coo}} +Other babel functions: \code{\link{chc2Out}}, + \code{\link{chc2pix}}, \code{\link{import_jpg}}, + \code{\link{import_tps}}, \code{\link{nef2Coe}}, + \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, + \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} } diff --git a/man/import_jpg.Rd b/man/import_jpg.Rd index 50aa56d2..7b3419a5 100644 --- a/man/import_jpg.Rd +++ b/man/import_jpg.Rd @@ -51,13 +51,10 @@ coo <- import_jpg() } } \seealso{ -Other babel functions: \code{\link{a2l}}, - \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, +Other babel functions: \code{\link{chc2Out}}, + \code{\link{chc2pix}}, \code{\link{import_StereoMorph_curve1}}, - \code{\link{import_tps}}, \code{\link{l2a}}, - \code{\link{l2m}}, \code{\link{m2a}}, \code{\link{m2d}}, - \code{\link{m2l}}, \code{\link{nef2Coe}}, + \code{\link{import_tps}}, \code{\link{nef2Coe}}, \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} } diff --git a/man/import_tps.Rd b/man/import_tps.Rd index 925291c7..939225ef 100644 --- a/man/import_tps.Rd +++ b/man/import_tps.Rd @@ -19,13 +19,10 @@ a list with components: And returns a list of coordinates, curves, scale } \seealso{ -Other babel functions: \code{\link{a2l}}, - \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, +Other babel functions: \code{\link{chc2Out}}, + \code{\link{chc2pix}}, \code{\link{import_StereoMorph_curve1}}, - \code{\link{import_jpg}}, \code{\link{l2a}}, - \code{\link{l2m}}, \code{\link{m2a}}, \code{\link{m2d}}, - \code{\link{m2l}}, \code{\link{nef2Coe}}, + \code{\link{import_jpg}}, \code{\link{nef2Coe}}, \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} } diff --git a/man/l2a.Rd b/man/l2a.Rd index 010ae10f..ac921c28 100644 --- a/man/l2a.Rd +++ b/man/l2a.Rd @@ -28,16 +28,14 @@ a <- l2a(l) a } \seealso{ -\link{a2l}. +Other bridges functions: \code{\link{a2l}}, + \code{\link{a2m}}, \code{\link{as_df}}, + \code{\link{l2m}}, \code{\link{m2a}}, \code{\link{m2d}}, + \code{\link{m2ll}}, \code{\link{m2l}} -Other babel functions: \code{\link{a2l}}, +Other bridges functions: \code{\link{a2l}}, \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, - \code{\link{import_StereoMorph_curve1}}, - \code{\link{import_jpg}}, \code{\link{import_tps}}, \code{\link{l2m}}, \code{\link{m2a}}, \code{\link{m2d}}, - \code{\link{m2l}}, \code{\link{nef2Coe}}, - \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, - \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} + \code{\link{m2ll}}, \code{\link{m2l}} } diff --git a/man/l2m.Rd b/man/l2m.Rd index 89cda773..5838783c 100644 --- a/man/l2m.Rd +++ b/man/l2m.Rd @@ -26,14 +26,9 @@ m \seealso{ \link{m2l}. -Other babel functions: \code{\link{a2l}}, +Other bridges functions: \code{\link{a2l}}, \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, - \code{\link{import_StereoMorph_curve1}}, - \code{\link{import_jpg}}, \code{\link{import_tps}}, \code{\link{l2a}}, \code{\link{m2a}}, \code{\link{m2d}}, - \code{\link{m2l}}, \code{\link{nef2Coe}}, - \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, - \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} + \code{\link{m2ll}}, \code{\link{m2l}} } diff --git a/man/m2a.Rd b/man/m2a.Rd index c91f9ec8..be0a4d2c 100644 --- a/man/m2a.Rd +++ b/man/m2a.Rd @@ -28,14 +28,9 @@ m2a(m) \seealso{ \link{a2m} the reverse function. -Other babel functions: \code{\link{a2l}}, +Other bridges functions: \code{\link{a2l}}, \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, - \code{\link{import_StereoMorph_curve1}}, - \code{\link{import_jpg}}, \code{\link{import_tps}}, \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2d}}, - \code{\link{m2l}}, \code{\link{nef2Coe}}, - \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, - \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} + \code{\link{m2ll}}, \code{\link{m2l}} } diff --git a/man/m2d.Rd b/man/m2d.Rd index 0c486712..0e55ee7e 100644 --- a/man/m2d.Rd +++ b/man/m2d.Rd @@ -22,14 +22,9 @@ m2d(wings[3]) \seealso{ \link{m2d} the reverse function. -Other babel functions: \code{\link{a2l}}, +Other bridges functions: \code{\link{a2l}}, \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, - \code{\link{import_StereoMorph_curve1}}, - \code{\link{import_jpg}}, \code{\link{import_tps}}, \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2l}}, \code{\link{nef2Coe}}, - \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, - \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} + \code{\link{m2ll}}, \code{\link{m2l}} } diff --git a/man/m2l.Rd b/man/m2l.Rd index 11598a93..2380f506 100644 --- a/man/m2l.Rd +++ b/man/m2l.Rd @@ -26,14 +26,9 @@ m \seealso{ \link{l2m}. -Other babel functions: \code{\link{a2l}}, +Other bridges functions: \code{\link{a2l}}, \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, - \code{\link{import_StereoMorph_curve1}}, - \code{\link{import_jpg}}, \code{\link{import_tps}}, \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{nef2Coe}}, - \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, - \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} + \code{\link{m2d}}, \code{\link{m2ll}} } diff --git a/man/m2ll.Rd b/man/m2ll.Rd new file mode 100644 index 00000000..0afe5a62 --- /dev/null +++ b/man/m2ll.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/babel-bridges.R +\name{m2ll} +\alias{m2ll} +\title{Used internally to hanle coo and cur in \code{Ldk} objects but may be +useful elsewhere} +\usage{ +m2ll(m, index = NULL) +} +\arguments{ +\item{m}{\code{matrix}, typically of (x; y) coordinates} + +\item{index}{\code{numeric}, the number of coordinates for every slice.} +} +\description{ +Used internally to hanle coo and cur in \code{Ldk} objects but may be +useful elsewhere +} +\examples{ +m2ll(wings[1], c(6, 4, 3, 5)) +} +\seealso{ +Other bridges functions: \code{\link{a2l}}, + \code{\link{a2m}}, \code{\link{as_df}}, + \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, + \code{\link{m2d}}, \code{\link{m2l}} +} + diff --git a/man/nef2Coe.Rd b/man/nef2Coe.Rd index 48f24208..53e75ebc 100644 --- a/man/nef2Coe.Rd +++ b/man/nef2Coe.Rd @@ -19,13 +19,10 @@ So if you have troubles importing your datasets, contact me, I can help. Or if y please let met know! } \seealso{ -Other babel functions: \code{\link{a2l}}, - \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, +Other babel functions: \code{\link{chc2Out}}, + \code{\link{chc2pix}}, \code{\link{import_StereoMorph_curve1}}, \code{\link{import_jpg}}, \code{\link{import_tps}}, - \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{m2l}}, \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} } diff --git a/man/ntsrow2Coo.Rd b/man/ntsrow2Coo.Rd index 1c1310d7..b215e069 100644 --- a/man/ntsrow2Coo.Rd +++ b/man/ntsrow2Coo.Rd @@ -31,13 +31,10 @@ please let met know! # wings <- Ldk(coo_list, fac=fac) } \seealso{ -Other babel functions: \code{\link{a2l}}, - \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, +Other babel functions: \code{\link{chc2Out}}, + \code{\link{chc2pix}}, \code{\link{import_StereoMorph_curve1}}, \code{\link{import_jpg}}, \code{\link{import_tps}}, - \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{m2l}}, \code{\link{nef2Coe}}, \code{\link{pix2chc}}, \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} } diff --git a/man/pProcrustes.Rd b/man/pProcrustes.Rd index 69fd1174..4faa3dd4 100644 --- a/man/pProcrustes.Rd +++ b/man/pProcrustes.Rd @@ -27,4 +27,7 @@ Directly borrowed from Claude (2008), and called \code{pPsup} there. \references{ Claude, J. (2008). Morphometrics with R. Analysis (p. 316). Springer. } +\seealso{ +Other procrustes functions:: \code{\link{fgProcrustes}} +} diff --git a/man/pix2chc.Rd b/man/pix2chc.Rd index 757065e5..c9a00165 100644 --- a/man/pix2chc.Rd +++ b/man/pix2chc.Rd @@ -24,13 +24,10 @@ Elliptic Fourier features of a closed contour. \seealso{ \link{chc2pix} -Other babel functions: \code{\link{a2l}}, - \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, +Other babel functions: \code{\link{chc2Out}}, + \code{\link{chc2pix}}, \code{\link{import_StereoMorph_curve1}}, \code{\link{import_jpg}}, \code{\link{import_tps}}, - \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{m2l}}, \code{\link{nef2Coe}}, \code{\link{ntsrow2Coo}}, \code{\link{tie_jpg_txt}}, \code{\link{tps2coo}} } diff --git a/man/stack.Coo.Rd b/man/stack.Coo.Rd index 481234bb..b793237b 100644 --- a/man/stack.Coo.Rd +++ b/man/stack.Coo.Rd @@ -16,10 +16,10 @@ \method{stack}{OutCoe}(x, nb.pts = 120, ...) \method{stack}{Ldk}(x, cols, borders, first.point = TRUE, centroid = TRUE, - ldk = TRUE, ldk.pch = 3, ldk.col = "#333333", ldk.cex = 0.5, - ldk_links = FALSE, ldk_confell = FALSE, ldk_contour = FALSE, - ldk_chull = FALSE, ldk_labels = FALSE, cur = TRUE, cur.pch = ".", - xy.axis = TRUE, title = substitute(x), ...) + ldk = TRUE, ldk.pch = 20, ldk.col = col_alpha("#000000", 0.3), + ldk.cex = 0.3, ldk_links = FALSE, ldk_confell = FALSE, + ldk_contour = FALSE, ldk_chull = FALSE, ldk_labels = FALSE, + cur = TRUE, cur_pch = 20, xy.axis = TRUE, title = substitute(x), ...) } \arguments{ \item{x}{The \code{Coo} object to plot.} diff --git a/man/tie_jpg_txt.Rd b/man/tie_jpg_txt.Rd index 99aec9e8..aaf6d4f8 100644 --- a/man/tie_jpg_txt.Rd +++ b/man/tie_jpg_txt.Rd @@ -19,13 +19,10 @@ Not optimized (images are read twice). Please do not hesitate to contact me should you have a particular case or need something. } \seealso{ -Other babel functions: \code{\link{a2l}}, - \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, +Other babel functions: \code{\link{chc2Out}}, + \code{\link{chc2pix}}, \code{\link{import_StereoMorph_curve1}}, \code{\link{import_jpg}}, \code{\link{import_tps}}, - \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{m2l}}, \code{\link{nef2Coe}}, \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, \code{\link{tps2coo}} } diff --git a/man/tps2Coo.Rd b/man/tps2Coo.Rd index f275c245..c752fe14 100644 --- a/man/tps2Coo.Rd +++ b/man/tps2Coo.Rd @@ -31,13 +31,10 @@ Ldk(coo=coo$coo, cur=coo$cur) } } \seealso{ -Other babel functions: \code{\link{a2l}}, - \code{\link{a2m}}, \code{\link{as_df}}, - \code{\link{chc2Out}}, \code{\link{chc2pix}}, +Other babel functions: \code{\link{chc2Out}}, + \code{\link{chc2pix}}, \code{\link{import_StereoMorph_curve1}}, \code{\link{import_jpg}}, \code{\link{import_tps}}, - \code{\link{l2a}}, \code{\link{l2m}}, \code{\link{m2a}}, - \code{\link{m2d}}, \code{\link{m2l}}, \code{\link{nef2Coe}}, \code{\link{ntsrow2Coo}}, \code{\link{pix2chc}}, \code{\link{tie_jpg_txt}} } diff --git a/vignettes/Momocs_speed_dating.R b/vignettes/Momocs_speed_dating.R deleted file mode 100644 index 79fb403a..00000000 --- a/vignettes/Momocs_speed_dating.R +++ /dev/null @@ -1,304 +0,0 @@ -## ---- echo=FALSE--------------------------------------------------------- -library(knitr) -opts_chunk$set(eval = TRUE, message=FALSE, - warnings=FALSE, results="hold") - -## ---- eval=FALSE--------------------------------------------------------- -# install.packages("devtools") -# devtools::install_github("vbonhomme/Momocs") - -## ---- eval=TRUE, echo=TRUE, message=FALSE-------------------------------- -library(Momocs) - -## ---- echo=FALSE, message=FALSE------------------------------------------ -shapes[18] %>% coo_sample(60) %>% coo_plot(points=TRUE) -olea[11] %>% coo_sample(32) %>% coo_plot(points=TRUE) -wings[1] %>% coo_plot(points=TRUE) - -## ------------------------------------------------------------------------ -shapes[18] %>% head() - -## ------------------------------------------------------------------------ -shapes # prints a brief summary -panel(shapes, names=TRUE) # base graphics -panel2(shapes) # ggplot2 graphics - -## ------------------------------------------------------------------------ -shp <- shapes[4] -coo_plot(shp) -# coo_plot is the base plotter for shapes -# but it can be finely customized, see ?coo_plot -coo_plot(shp, col="grey80", border=NA, centroid=FALSE, main="Meow") - -## ------------------------------------------------------------------------ -coo_plot(coo_center(shp), main="centered Meow") -coo_plot(coo_sample(shp, 64), points=TRUE, pch=20, main="64-pts Meow") - -## ------------------------------------------------------------------------ -shapes[4] %>% coo_smooth(5) %>% coo_sample(64) %>% coo_scale() %>% coo_plot() - -# pipes can be turned into custom function -cs64 <- function(x) x %>% coo_sample(64) %>% coo_scale() %>% coo_center() -shapes[4] %>% cs64 %>% coo_plot() # note the axes - -## ------------------------------------------------------------------------ -bot %>% - coo_center %>% coo_scale %>% - coo_alignxax() %>% coo_slidedirection("N") %T>% - print() %>% stack() - -## ------------------------------------------------------------------------ -data(bot) -bot -panel(bot, fac="type", names=TRUE) -stack(bot) - -## ------------------------------------------------------------------------ -coo_oscillo(bot[1], "efourier") - -## ------------------------------------------------------------------------ -Ptolemy(bot[1]) - -## ------------------------------------------------------------------------ -calibrate_harmonicpower(bot) -calibrate_deviations(bot) -calibrate_reconstructions(bot) - -## ------------------------------------------------------------------------ -bot.f <- efourier(bot, nb.h=10) -bot.f - -## ------------------------------------------------------------------------ -hist(bot.f, drop=0) -boxplot(bot.f, drop=1) -stack(bot.f) - -## ------------------------------------------------------------------------ -bot.p <- PCA(bot.f) -class(bot.p) # a PCA object, let's plot it -plot(bot.p) - -## ---- message=FALSE, error=FALSE, warning=FALSE, results="hide"---------- -# raw molars dataset -stack(molars, title = "Non-aligned molars") -# Procrustes-aligned and slided molars -mol.al <- fgProcrustes(molars) %>% coo_slidedirection("W") -stack(mol.al, title="Aligned molars") - -# Now compare PCA and morphospace using the 1st harmonic alignment -molars %>% efourier(norm=TRUE) %>% PCA() %>% plot("type") -# and the a priori normalization -molars %>% efourier(norm=FALSE) %>% PCA() %>% plot("type") - -## ------------------------------------------------------------------------ -olea -stack(olea, fac="view") # already aligned \o/ -panel(olea, names="ind") # another family picture - -## ------------------------------------------------------------------------ -op <- opoly(olea) # orthogonal polynomials -class(op) # an OpnCoe, but also a Coe -op.p <- PCA(op) # we calculate a PCA on it -class(op.p) # a PCA object -plot(PCA(op), ~domes+var) # notice the formula interface to combine factors - -## ---- message=FALSE------------------------------------------------------ -table(olea, "view", "var") -# we drop 'Cypre' since there is no VL for 'Cypre' var -olea %>% filter(var != "Cypre") %>% - # split, do morphometrics, combine - chop(view) %>% lapply(opoly) %>% combine() %T>% - # we print the OpnCoe object, then resume to the pipe - print() %>% - # note the two views in the morphospace - PCA() %>% plot("var") - -## ---- message=FALSE, echo=FALSE------------------------------------------ -stack(wings) -w.al <- fgProcrustes(wings) -stack(w.al) -ldk_confell(w.al$coo, col = "red") -ldk_chull(w.al$coo) -ldk_contour(w.al$coo) -ldk_labels(mshapes(w.al$coo)) - -## ------------------------------------------------------------------------ -hearts -panel(hearts, fac="aut", names="aut") - -## ------------------------------------------------------------------------ -ht <- measure(hearts, coo_area, coo_circularity, d(1, 3)) -ht %>% PCA() %>% plot("aut", pch=20, ellipsesax=F, ellipse=T, loadings=T) - -## ------------------------------------------------------------------------ -flower -flower %>% PCA() %>% plot("sp", loadings=TRUE) - -## ---- message=FALSE------------------------------------------------------ -bot.f <- efourier(bot) - -## ------------------------------------------------------------------------ -bot.p <- PCA(bot.f) -plot(bot.p) - -## ------------------------------------------------------------------------ -plot(bot.p, "type") # equivalent to plot(bot.p, 1) - -## ------------------------------------------------------------------------ -plot(bot.p, 1, ellipses=TRUE, ellipsesax = FALSE, pch=c(4, 5)) -plot(bot.p, 1, chull=TRUE, pos.shp = "full_axes", abbreviate.labelsgroups = TRUE, points=FALSE, labelspoints = TRUE) -plot(bot.p, 1, pos.shp="circle", stars=TRUE, palette=col_qual) - -## ------------------------------------------------------------------------ -plot2(bot.p, "type") - -## ------------------------------------------------------------------------ -scree(bot.p) -scree_plot(bot.p) -boxplot(bot.p, 1) -PCcontrib(bot.p) - -## ------------------------------------------------------------------------ -TraCoe(iris[, -5], fac=data.frame(sp=iris$Species)) %>% - PCA() %>% plot("sp", loadings=TRUE) -# or -PCA(iris[, -5], fac=data.frame(sp=iris$Species)) %>% - plot("sp", chull=TRUE, ellipses=TRUE, conf_ellipses = 0.9) - -## ---- eval=FALSE--------------------------------------------------------- -# #LDA(bot.f, 1) -# # we work on PCA scores -# bot.l <- LDA(bot.p, 1) -# # print a summary, along with the leave-one-out cross-validation table. -# bot.l -# # plot.LDA works pretty much with the same grammar as plot.PCA -# # here we only have one LD -# plot(bot.l) -# # plot the cross-validation table -# plot_CV(bot.l) # tabular version -# plot_CV2(bot.l) # arrays version - -## ------------------------------------------------------------------------ -MANOVA(bot.p, "type") - -## ------------------------------------------------------------------------ -MANOVA_PW(bot.p, "type") - -## ---- eval=FALSE--------------------------------------------------------- -# CLUST(bot.p, 1) - -## ------------------------------------------------------------------------ -KMEANS(bot.p, centers = 5) - -## ------------------------------------------------------------------------ -# mean shape -bot.f %>% mshapes() %>% coo_plot() -# mean shape, per group -bot.ms <- mshapes(bot.f, 1) -beer <- bot.ms$shp$beer %T>% coo_plot(border="blue") -whisky <- bot.ms$shp$whisky %T>% coo_draw(border="red") -legend("topright", lwd=1, - col=c("blue", "red"), legend=c("beer", "whisky")) - -## ---- results="markup"--------------------------------------------------- -data(olea) -olea - -# slice: select individuals based on their position -slice(olea, 1:5) -slice(olea, -(1:100)) - -# filter: select individual based on a logical condition -filter(olea, domes=="cult", view!="VD") - -# select: pick, reorder columns from the $fac -select(olea, 1, Ind=ind) - -# rename: rename columns (select can also do it) -rename(olea, domesticated=domes) - -# mutate: add new columns -mutate(olea, fake=factor(rep(letters[1:2], each=105))) - -# transmute: add new columns and drop others -transmute(olea, fake=factor(rep(letters[1:2], each=105))) - -## ------------------------------------------------------------------------ -olea %>% -filter(domes=="cult", view=="VD") %>% -rename(domesticated=domes) %>% -select(-ind) - -## ------------------------------------------------------------------------ -table(olea, "view", "var") -# we drop 'Cypre' since there is no VL for 'Cypre' var -olea %>% filter(var != "Cypre") %>% - # split, do morphometrics, combine - chop(view) %>% lapply(opoly) %>% combine() %>% - # note the two views in the morphospace - PCA() %>% plot("var") - -## ---- eval=FALSE--------------------------------------------------------- -# names(bot) -# length(bot) -# table(olea, "var", "domes") -# Ntable(olea, "var", "domes") -# bot[1] -# bot[1:5] -# bot$brahma -# bot$type - -## ---- eval=FALSE--------------------------------------------------------- -# library(geomorph) -# data(pupfish) -# str(pupfish) -# # so $coords will become $coo, and -# # all other components will be turned into a data.frame to feed $fac -# # with a single line -# Ldk(coo=pupfish$coords %>% a2l, -# fac=pupfish[-1] %>% as.data.frame()) - -## ---- eval=FALSE--------------------------------------------------------- -# save(bot, file="Bottles.rda") -# # closing R, going to the beach, back at work -# load("Bottles.rda") # bot is back - -## ---- eval=FALSE--------------------------------------------------------- -# bot %>% as_df # then %>% write.table -# bot %>% efourier %>% export -# bot %>% efourier %>% PCA %>% export - -## ---- eval=FALSE--------------------------------------------------------- -# # from Coo objects -# bot$coo -# bot$fac -# -# # from Coe objects -# bot.f$coe -# bot.f$fac -# as_df(bot.f) -# -# # from PCA objects -# bot.p$x # scores -# bot.p$rotation # rotation matrix - -## ------------------------------------------------------------------------ -panel(bot) -panel2(bot) - -## ------------------------------------------------------------------------ -library(ggplot2) -gg <- panel2(bot) -gg + theme_minimal() - -## ------------------------------------------------------------------------ -# we build a ggplot object from a shape turned into a data.frame -shapes[4] %>% m2d() %>% ggplot() + - aes(x, y) + geom_path() + coord_equal() + - labs(title="ggplot2 Meow") + theme_minimal() - -## ------------------------------------------------------------------------ -bot.p %>% as_df() %>% ggplot() + - aes(x=PC1, y=PC2, col=type) + coord_equal() + - geom_point() + geom_density2d() + theme_light() - diff --git a/vignettes/Momocs_speed_dating.Rmd b/vignettes/Momocs_speed_dating.Rmd index 519f2c85..661e86f4 100644 --- a/vignettes/Momocs_speed_dating.Rmd +++ b/vignettes/Momocs_speed_dating.Rmd @@ -541,8 +541,8 @@ bot$type ## Babel import/export There are various morphometrics formats in the wild, almost as much as softwares. Momocs tries to create bridges between them, all gathered in the **Babel** family. -### Within R -You can convert from/to array, matrix, list or data.frame with the functions `{a, m, l, d}2{a, m, l, d}`. For instance, `l2a` converts a list into an array that you can use with `geomorph`; `a2l` does the inverse operation +### Bridges within R +You can convert from/to array, matrix, list or data.frame with the functions `{a, m, l, d}2{a, m, l, d}`. For instance, `l2a` converts a list into an array that you can use with `geomorph`; `a2l` does the inverse operation. Imagine you want to import pupfish from `geomorph` as a `Ldk` object: diff --git a/vignettes/Momocs_speed_dating.html b/vignettes/Momocs_speed_dating.html deleted file mode 100644 index 431c0995..00000000 --- a/vignettes/Momocs_speed_dating.html +++ /dev/null @@ -1,919 +0,0 @@ - - - - - - - - - - - - - - -Momocs speed dating - - - - - - - - - - - - - - - - - - -
- -
- -
-

Preliminaries

-
-

Abstract

-

Momocs aims to provide a complete and convenient toolkit for morphometrics. It is intended for scientists interested in describing quantitatively the shape, and its variations, of the objects they study.

-

In the last decade, R has become the open-source lingua franca for statistics, and morphometrics known its so-called ‘revolution’. Nevertheless, morphometric analyses still have to be carried out using various software packages, for which source code is mostly unavailable or copyrighted. Moreover, most of existing software packages cannot be extended and their bugs are hard to detect and thus correct. This situation is detrimental to morphometrics; time is wasted, analyses are restricted to available methods, and last but not least, are poorly reproducible. This impedes collaborative effort both in software development and in morphometric studies.

-

By gathering the common morphometric approaches in an open-source environment and welcoming contributions, Momocs is an (work-in-progress) attempt to solve this twofold problem and to push morphometrics one step further.

-

It hinges on the core functions published in the must-have Morphometrics with R by Julien Claude (2008), but has been further extended to allow other shape description systems. So far, configurations of landmarks, outlines and open outline analyses, along with some facilities for traditional morphometrics have been implemented.

-

Prior to analysis, Momocs can be used to acquire and manipulate data or to import/export from/to other formats. Momocs also has the facility for a wide range of multivariate analyses and production of the companion graphics. Thus a researcher will find that just a few lines of code will provide initial results, but the methods implemented can be finely tuned and extended according to the user’s needs.

-
    -
  • See Momocs features.
  • -
  • If you use it, cite it: citation("Momocs").
  • -
  • This citation refers to an obsolete version of Momocs, only handling outline analyses. The next one is in preparation.
  • -
-
-
-

Survival tips

-
    -
  • This vignette gently introduces Momocs; more specific help can be find in function’s helfiles, for instance ?efourier.
  • -
  • There is an online (and much nicer) version of this manual that can be accessed with Momocs_help("efourier").
  • -
  • Feel free to contribute to Momocs through GitHub: report issues, ask for new features, share data and methods, correct typos, write better vignettes, helpfiles, or whatever pleases you. If you have never heard of GitHub, that’s definitely worth a look.
  • -
  • Feel free to drop me a line, should you need a hand or would like to collaborate with me: bonhomme.vincent@gmail.com.
  • -
-
-
-

Get, install and use it

-

First, of all, let’s download the last version of Momocs. You will need to install the devtools package to get it from my GitHub repository :

-
install.packages("devtools")
-devtools::install_github("vbonhomme/Momocs")
-

The typical install_packages("Momocs") is not recommended as Momocs is still under active development, not compatible with frequent, time-consuming, and overall boring CRAN submission.

-

We can start using Momocs, as long as it has been loaded with :

-
library(Momocs)
-
-
-
-

Design

-

Keywords used all accross Momocs are introduced here in bold.

-

Morphometrics is the ugly job of turning beautiful shapes into quantitative variables. Just kidding, that’s pretty exciting.

-

A shape is defined as a collection of (x; y) coordinates. No 3D yet but different families can be handled: outlines, here in a first-quarter moon ; open outlines, here is the sterile valve of an olive stone; configuration of landmarks; here, hologous points from a mosquito wing.

-

-

They are all single shapes defined by a matrix of (x; y) coordinates; here are the first points of the moon:

-
shapes[18] %>% head()
-
##      [,1] [,2]
-## [1,]  200   50
-## [2,]  199   49
-## [3,]  198   49
-## [4,]  197   50
-## [5,]  196   50
-## [6,]  195   49
-

A few dozens of operations on single shapes are implemented such as: plotting, centering, calculating areas, etc. They can be accessed with apropos("coo_"). But working on single shapes is quite boring.

-

Shapes can be organized into a collection of coordinates: a Coo object that carries:

- -

One can do several things with a Coo object: visualize it, apply morphometric operations, handle the data it contains, but in the end, a __ morphometric method__ to turn coordinates into coefficients.

-

Morphometrics on coordinates produce a collection collections of coefficients: a Coe objects that carries:

- -

This can be summarized as follows:

- - - - - - - - - - - - - - - - - - - -
Coo+Morphometric method=Coe
(x;y) coordinates+appropriate method=quantitative variables
-

Thus Coo objects are collections of coordinates that become Coe objects when an appropriate morphometric method is applied on them.

-

The different families of shape sometimes implies or requires particular operations on them. Some operations on shapes are generic in that they do not depend of the family. For instance, centering a configuration of landmarks or an outline, or calculating their centroid size is, mathematically, the same generic operation. But some operations on shapes are specific to a peculiar family. For instance, calculating elliptical Fourier transforms on a configuration of landmarks makes no sense.

-

Momocs implement this desirable behavior and defines classes and subclasses, as S3 objects.

- - - - - - - - - - - - - - - - - - - - - - - - - -
CooMorphometrics methodsCoe
OutCoo (outlines)efourier, rfourier, tfourierOutCoe
OpnCoo (open outlines)npoly, opoly, dfourierOpnCoe
LdkCoo (configuration of landmarks)fgProcrustes, slideLdkCoe
-

In other words:

- -

Finally, generic and specific operations can be applied to the Coe objects, chiefly multivariate methods, capitalicized: PCA, LDA, CLUST, MANOVA, etc.

-

Overall, Momocs implements a simple and consistent grammar that is detailed below.

-

Last but not least, if you’re familiar with modern R and the Hadley-verse, you should feel home as ggplot2 graphics, dplyr verbs and magrittr pipes are implemented available.

-
-
-

Single shapes

-

Let’s load one of the Momocs datasets, some various outlines (an Out object):

-
shapes                    # prints a brief summary
-panel(shapes, names=TRUE) # base graphics
-

-
panel2(shapes)            # ggplot2 graphics
-

-
## An Out object with: 
-## --------------------
-##  - $coo: 30 outlines (836 +/- 255 coordinates, all closed)
-##  - $fac: No classifier defined in $fac
-

shapes is one of the datasets bundled with Momocs. It’s (“lazy”) loaded in memory as soon as you call it, no need for data(shapes). To see all Momocs’ datasets, try data(package="Momocs"). These datasets are all Coo objects (try class(bot)), ie collection of shapes. One can do many things on a Coo object, as above, eg printing a summary of it (just by typing its name), plotting a family picture with panel or panel2. Note the 2 that refers to a ggplot2 variant of a given plot.

-

So far, we’re interested in single shapes so let’s extract the 4th shape from shapes, using the traditional syntax. We plot it with coo_plot that comes with several options for plotting all families of shapes.

-
shp <- shapes[4]
-coo_plot(shp)
-

-
# coo_plot is the base plotter for shapes
-# but it can be finely customized, see ?coo_plot
-coo_plot(shp, col="grey80", border=NA, centroid=FALSE, main="Meow")
-

-

Let’s now do some basic operations on this shape. They all named coo_* and you can have the full list with apropos("coo_"). coo_* family encompasses:

- -
coo_plot(coo_center(shp), main="centered Meow")
-

-
coo_plot(coo_sample(shp, 64), points=TRUE, pch=20, main="64-pts Meow")
-

-

Momocs makes use of maggritr’s pipe operators. A nice introduction can be found there. magrittr requires a (very small) cerebral gymnastics at the beginning but the benefits are huge, for R as a whole. It makes things clearer, it: saves typing; reduces intermediate variable assignation; reads from left to right; substantiates the pipe we (should) have in mind. magrittr’s pipes are already loaded with Momocs.

-
shapes[4] %>% coo_smooth(5) %>% coo_sample(64) %>% coo_scale() %>% coo_plot()
-

-
# pipes can be turned into custom function
-cs64 <- function(x) x %>% coo_sample(64) %>% coo_scale() %>% coo_center()
-shapes[4] %>% cs64 %>% coo_plot() # note the axes
-

-

The most familiar operation can directly be applied on Coo objects:

-
bot %>% 
-  coo_center %>% coo_scale %>% 
-  coo_alignxax() %>% coo_slidedirection("N") %T>% 
-  print() %>% stack()
-

-
## An Out object with: 
-## --------------------
-##  - $coo: 40 outlines (162 +/- 21 coordinates, all unclosed)
-##  - $fac: 1 classifier:
-##      'type' (factor 2): beer, whisky.
-

Notice that before the stack operation, we still have a Coo object. And by the way, pipes can also be defined on Momocs objects.

-
-
-

Morphometrics

-
-

Outline analysis

-

A word about data import: you can extract outlines from a list of black masks over a white background, as .jpg images with import_jpg. Have a look to helpfiles (import_jpg and import_jpg1) for more details. Here we do not bother with import since we will use the bottles outlines dataset bundled with Momocs.

-
data(bot)
-bot
-panel(bot, fac="type", names=TRUE)
-

-
stack(bot)
-

-
## An Out object with: 
-## --------------------
-##  - $coo: 40 outlines (162 +/- 21 coordinates, all unclosed)
-##  - $fac: 1 classifier:
-##      'type' (factor 2): beer, whisky.
-

Here we will illustrate outline analysis with some elliptical Fourier transforms (but the less used - and tested - radii variation Fourier transforms and tangent angle Fourier transforms are also implemented with rfourier and tfourier).

-

The idea behind elliptical Fourier transforms is to fit the x and y coordinates separately, that is the blue and red curves below:

-
coo_oscillo(bot[1], "efourier")
-

-

Graphically, this is equivalent to fitting Ptolemaic ellipses on the plane:

-
Ptolemy(bot[1])
-

-

Let’s calibrate the number of harmonics required. More details can be found in their respective help files.

-
calibrate_harmonicpower(bot)
-

-
calibrate_deviations(bot)
-

-
calibrate_reconstructions(bot)
-

-
##  * Method not provided. efourier is used.
-##   90%   95%   99% 99.9% 
-##     5     5    10    17 
-##  * Method not provided. efourier is used.
-##  * Method not provided. efourier is used.
-

Here, 10 harmonics gather 99% of the harmonic power. If you’re happy with this criterium, you can even omit nb.h in efourier : that’s the default parameter.

-
bot.f <- efourier(bot, nb.h=10)
-bot.f
-
## An OutCoe object [ elliptical Fourier analysis ]
-## --------------------
-##  - $coe: 40 outlines described, 10 harmonics
-##  - $coe: 1st harmonic coefficients from random individuals: 
-##              A1     A2    A3 B1     B2     B3 C1     C2     C3    D1
-## kingfisher    1  0.008 0.095  0  0.000  0.000  0  0.001 -0.002 0.304
-## latrappe      1  0.018 0.060  0  0.000  0.000  0  0.002  0.001 0.467
-## nicechouffe   1  0.015 0.091  0  0.001  0.000  0 -0.001  0.000 0.313
-## glendronach   1  0.003 0.095  0  0.000  0.000  0  0.000  0.001 0.288
-## highlandpark  1 -0.002 0.070  0 -0.001 -0.001  0 -0.002  0.001 0.422
-##                  D2    D3
-## kingfisher   -0.069 0.044
-## latrappe     -0.087 0.044
-## nicechouffe  -0.091 0.044
-## glendronach  -0.069 0.040
-## highlandpark -0.079 0.045
-## etc.
-##  - $fac: 1 classifier:
-##      'type' (factor 2): beer, whisky.
-

bot.f is a Coe object (and even an OutCoe), you have have a look to the help files to go deeper into Momocs classes.

-

Let’s have a look to the amplitude of fitted coefficients. We can also reconstruct fitted outlines, directly.

-
hist(bot.f, drop=0)
-

-
boxplot(bot.f, drop=1)
-

-
stack(bot.f)
-

-

Now, we can calculate a PCA on the Coe object and plot it, along with morphospaces, calculated on the fly.

-
bot.p <- PCA(bot.f)
-class(bot.p)        # a PCA object, let's plot it
-plot(bot.p)
-

-
## [1] "PCA"    "prcomp"
-

Amazing but we will do much better afterwards.

-

The question of normalization in elliptical Fourier transforms is central. Normalization can either be done beforehand, with geometric operations, or afterhand, directly on the matrix of Fourier coefficients and consuming the first harmonic. In brief, I’m not a big fan of the “us the first harmonics and see what happens” strategy, as some biases can be introduced (and actually quite hard to detect), particularly on rounded/ellipsoid shapes. More can be found in ?efourier.

-

Here is an example of such bias from the molars dataset generously shared by Cornu and Detroit.

-
# raw molars dataset
-stack(molars, title = "Non-aligned molars")
-

-
# Procrustes-aligned and slided molars
-mol.al <- fgProcrustes(molars) %>% coo_slidedirection("W")
-stack(mol.al, title="Aligned molars")
-

-
# Now compare PCA and morphospace using the 1st harmonic alignment
-molars %>% efourier(norm=TRUE) %>% PCA() %>% plot("type")
-

-
# and the a priori normalization 
-molars %>% efourier(norm=FALSE) %>% PCA() %>% plot("type")
-

-

Finally, you can drop some harmonics with rm_harm. And methods that removes the bilateral (a)symmetry are implemented: rm_Asym and rm_Sym, while symmetry calculates some related indices.

-
-
-

Open outlines

-

Open outlines are curves. Methods actually implemented are:

-
    -
  • npoly that fit natural polynomials;
  • -
  • opoly that fit orthogonal (also called Legendre’s) polynomials;
  • -
  • dfourier for the discrete cosine transform.
  • -
-

Note that opoly and npoly can only be used on simple curves, curves that have at most one y for any x coordinates, at least under a given orientation. dfourier can fit complex curves, curves “that bak on their feets”.

-

Here, we will work on the fertile valves of olive stones, a (very partial) dataset provided by my colleagues Terral, Ivorra, and others.

-

They have two orthogonal views (a lateral and a dorsal view). See the paper cited in ?olea for more details. Let’s explore it a bit:

-
olea
-stack(olea, fac="view")     # already aligned \o/
-

-
panel(olea, names="ind")    # another family picture
-

-
## An Opn object with: 
-## --------------------
-##  - $coo: 210 open outlines (99 +/- 4 coordinates)
-##  - $fac: 4 classifiers:
-##      'var' (factor 4): Aglan, Cypre, MouBo1, PicMa.
-##      'domes' (factor 2): cult, wild.
-##      'view' (factor 2): VD, VL.
-##      'ind' (factor 30): O1, O10, O11, O12, O13, O14, O15, O16, O17, O18, O19 ... + 19 more.
-

Now, we gonna calculate opoly on it and plot the result of the PCA. Notice how consistent is the grammar and the objects obtained:

-
op <- opoly(olea)           # orthogonal polynomials
-class(op)                   # an OpnCoe, but also a Coe
-op.p <- PCA(op)             # we calculate a PCA on it
-class(op.p)                 # a PCA object
-plot(PCA(op), ~domes+var)   # notice the formula interface to combine factors
-

-
##  * 'nb.pts' missing and set to:  91 
-##  * 'degree' missing and set to:  5 
-## [1] "OpnCoe" "Coe"   
-## [1] "PCA"    "prcomp"
-

But this is perfectly wrong! We merged the two views are if they were different individuals. Momocs can first chop or filter the whole dataset to separate the two views, do morphometrics on them, and combine them afterwards.

-
table(olea, "view", "var") 
-# we drop 'Cypre' since there is no VL for 'Cypre' var
-olea %>% filter(var != "Cypre") %>%              
-  # split, do morphometrics, combine
-  chop(view) %>% lapply(opoly) %>% combine() %T>%
-   # we print the OpnCoe object, then resume to the pipe
-  print() %>%
-  # note the two views in the morphospace
-  PCA() %>% plot("var")
-

-
##     var
-## view Aglan Cypre MouBo1 PicMa
-##   VD    30    30     30    30
-##   VL    30     0     30    30
-##  * 'nb.pts' missing and set to:  91 
-##  * 'degree' missing and set to:  5 
-##  * 'nb.pts' missing and set to:  91 
-##  * 'degree' missing and set to:  5 
-## An OpnCoe object [ combined: opoly + opoly analyses ]
-## --------------------
-##  - $coe: 90 open outlines described
-##  - $baseline1: (-0.5; 0; -0.5; 0)
-##  - $baseline2: (0.5; 0; 0.5; 0)
-##  - $coe: 1st coefficients from random open outlines: 
-##                    Intercept    x1     x2    x3     x4     x5
-## 0001-cAglan_O18VD      0.184 0.030 -0.722 0.057 -0.102 -0.030
-## 0023-cPicMa_O17VD      0.162 0.082 -0.602 0.030 -0.077 -0.014
-## 0023-cPicMa_O3VD       0.180 0.019 -0.695 0.000 -0.125  0.026
-## 0125-wMouBo1_O23VD     0.249 0.037 -1.025 0.021 -0.183  0.027
-## 0125-wMouBo1_O24VD     0.223 0.081 -0.902 0.042 -0.159 -0.003
-## etc.
-##  - $fac: 4 classifiers:
-##      'var' (factor 4): Aglan, Cypre, MouBo1, PicMa.
-##      'domes' (factor 2): cult, wild.
-##      'view' (factor 2): VD, VL.
-##      'ind' (factor 30): O1, O10, O11, O12, O13, O14, O15, O16, O17, O18, O19 ... + 19 more.
-

Now the PCA is done on the combination of two OpnCoe objects, each one resulting from an independant opoly call. That is the meaning of the [ combined: opoly + opoly analyses ] printed by the pipe above. Momocs can combine up to four different views.

-
-
-

Configuration of landmarks

-

Landmarks methods are being implemented in Momocs (as of nov 2015). Full generalized Procrustes methods are available, and sliding methods on semi landmarls will soon be. Here is a first glimpse.

-

First, let’s have a look to graphics facilities

-
-
-

Traditionnal morphometrics

-

Traditional morphometrics lose geometries: from the variables, you can’t unambiguously reconstruct the shape. Every shape is described by a combination of measurements, (inter landmark distance, quantitative variables, scalar descriptor, etc.)

-

Momocs provides some basics utilities to work with such objects in the TraCoe class. There is not TraCoo per se but it can be obtained from any Coo with the measure method. Let’s take the hearts dataset that comes from handdrawn heart shapes from my former colleagues at the French Intitute of Pondicherry:

-
hearts
-panel(hearts, fac="aut", names="aut")
-

-
## An Out object with: 
-## --------------------
-##  - $coo: 240 outlines (80 +/- 0 coordinates, all unclosed)
-##  - $ldk: 4 landmark(s) defined
-##  - $fac: 1 classifier:
-##      'aut' (factor 8): ced, jeya, mat, ponnu, remi, rom, ruks, vince.
-

Notice that there are 4 landmarks defined on them. Such landmarks on outlines can be: defined withdef_ldk(), retrieved with get_ldk(), and overall used to align outlines with fgProcrustes(). You can compare: hearts %>% stack() with hearts %>% fgProcrustes() %>% coo_slide(ldk=1) %>% stack().

-

Let’s describe these hearts with scalar descriptors: area, circularity and the distance between the 1st and the 3rd bumps of the hearts. measure is of great help. Note the loadings.

-
ht <- measure(hearts, coo_area, coo_circularity, d(1, 3))
-ht %>% PCA() %>% plot("aut", pch=20, ellipsesax=F, ellipse=T, loadings=T)
-

-

Again, there are plenty of scalar descriptors of shape, which names starts with coo_*, apropos("coo_").

-

Such a TraCoe is provided in the flower dataset which is simply a rearranged iris. Once again, note the grammar consistency.

-
flower
-flower %>% PCA() %>% plot("sp", loadings=TRUE)
-

-
## A TraCoe object --------------------
-##  - $coe: 150 shapes described with 4 variables
-##  - $fac: 1 classifier:
-##      'sp' (factor 3): setosa, versicolor, virginica.
-

Note that, by default, PCA on TraCoe object first centers and scales variables. This can be changed, see ?PCA.

-
-
-
-

Multivariate statistics

-

This section will mainly be illustrated with bot, and consequently outline analysis, but it works the same on any Coe object, resulting from open outlines, configuration of landmarks, traditional morphometrics, etc.

-
bot.f <- efourier(bot)
-
##  * 'nb.h' not provided and set to 10 (99% harmonic power).
-
-

PCA: Principal Component Analysis

-

Let’s see the main components of shape variability with a Principal Component Analysis.

-
bot.p <- PCA(bot.f)
-plot(bot.p)
-

-

Morphological spaces are reconstructed on the fly with plot.PCA. We call it plot.PCA because it uses the familiar plot but on the particular PCA class (type class(bot.p)). We may want to display the two groups saved in bot$fac. Just type the id of the column or its name.

-
plot(bot.p, "type") # equivalent to plot(bot.p, 1)
-

-

plot.PCA has many arguments and examples below will give a glimpse, but see ?plot.PCA for the full list.

-
plot(bot.p, 1, ellipses=TRUE, ellipsesax = FALSE, pch=c(4, 5))
-

-
plot(bot.p, 1, chull=TRUE, pos.shp = "full_axes", abbreviate.labelsgroups = TRUE, points=FALSE, labelspoints = TRUE)
-

-
plot(bot.p, 1, pos.shp="circle", stars=TRUE, palette=col_qual)
-

-

You have a ggplot2 alternative, that is not completely consistent:

-
plot2(bot.p, "type")
-

-

And other helper functions for the PCA class:

-
scree(bot.p)
-scree_plot(bot.p)
-

-
boxplot(bot.p, 1)
-

-
PCcontrib(bot.p)
-

-
## Source: local data frame [10 x 3]
-## 
-##      axis  proportion    cumsum
-##    (fctr)       (dbl)     (dbl)
-## 1       1 0.761231874 0.7612319
-## 2       2 0.169653739 0.9308856
-## 3       3 0.029390036 0.9602756
-## 4       4 0.013455334 0.9737310
-## 5       5 0.008596806 0.9823278
-## 6       6 0.007189450 0.9895172
-## 7       7 0.003063352 0.9925806
-## 8       8 0.001904873 0.9944855
-## 9       9 0.001592046 0.9960775
-## 10     10 0.001223167 0.9973007
-

By the way, you can use Momocs plotters to plot non-morphometric datasets. Using a TraCoe object is an option, but PCA also works fine. Let’s see an example with iris dataset:

-
TraCoe(iris[, -5], fac=data.frame(sp=iris$Species)) %>% 
-  PCA() %>% plot("sp", loadings=TRUE)
-

-
# or
-PCA(iris[, -5], fac=data.frame(sp=iris$Species)) %>%
-  plot("sp", chull=TRUE, ellipses=TRUE, conf_ellipses = 0.9)
-

-
-
-

LDA: Linear Discriminant Analysis

-

We can also calculate a Linear Discriminant Analysis on the PCA scores, or on the Coe object, directly on the matrix of coefficients but we may encounter collinearity between variables. Try the following:

-
#LDA(bot.f, 1)
-# we work on PCA scores
-bot.l <- LDA(bot.p, 1)
-# print a summary, along with the leave-one-out cross-validation table. 
-bot.l 
-# plot.LDA works pretty much with the same grammar as plot.PCA
-# here we only have one LD
-plot(bot.l)
-# plot the cross-validation table
-plot_CV(bot.l)  # tabular version
-plot_CV2(bot.l) # arrays version
-

Finally, if you need to classify using LDA methods, see classify.

-
-
-

MANOVA: Multivariate Analysis of variace

-

We can test for a difference in the distribution of PC scores with:

-
MANOVA(bot.p, "type")
-
##  * PC axes 1 to 7 were retained.
-##           Df Hotelling-Lawley approx F num Df den Df   Pr(>F)    
-## fac        1           2.8388   12.977      7     32 8.88e-08 ***
-## Residuals 38                                                     
-## ---
-## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
-

We can also calculate pairwise combination between every levels of a fac. Here we just have two levels, so a single pairwise combination but the syntax is:

-
MANOVA_PW(bot.p, "type")
-
##  * PC axes 1 to 7 were retained
-## $stars.tab
-##      beer whisky
-## beer      ***   
-## 
-## $summary (see also $manovas)
-##               Df Pillai approx F num Df den Df   Pr(>F)
-## beer - whisky  1 0.7395    12.98      7     32 8.88e-08
-
-
-

CLUST: Hierarchical clustering

-

A hierarchical classification now. It relies on ggtree which is itself under active development. So you may have trouble to make this command work.

-
CLUST(bot.p, 1)
-

Monophyly is plotted by default. Many options can be found in ?CLUST

-
-
-

KMEANS: K-means clustering

-

A very minimal k-means clustering is implemented:

-
KMEANS(bot.p, centers = 5)
-

-
## K-means clustering with 5 clusters of sizes 5, 6, 6, 5, 18
-## 
-## Cluster means:
-##           PC1          PC2
-## 1  0.06730453  0.050371247
-## 2  0.10184224 -0.028875902
-## 3 -0.02673158  0.017713990
-## 4  0.02497106 -0.006671549
-## 5 -0.05066899 -0.008418168
-## 
-## Clustering vector:
-##         brahma          caney         chymay         corona    deusventrue 
-##              5              3              2              5              3 
-##          duvel   franziskaner     grimbergen        guiness     hoegardeen 
-##              2              5              4              4              5 
-##        jupiler     kingfisher       latrappe lindemanskriek    nicechouffe 
-##              5              5              2              3              3 
-##     pecheresse   sierranevada     tanglefoot          tauro      westmalle 
-##              5              4              2              5              5 
-##          amrut    ballantines      bushmills         chivas        dalmore 
-##              5              2              5              1              1 
-##   famousgrouse    glendronach   glenmorangie   highlandpark    jackdaniels 
-##              5              5              5              2              4 
-##             jb  johnniewalker       magallan     makersmark           oban 
-##              3              5              5              1              5 
-##     oldpotrero      redbreast         tamdhu     wildturkey         yoichi 
-##              1              1              5              3              4 
-## 
-## Within cluster sum of squares by cluster:
-## [1] 0.002720829 0.006121728 0.001886406 0.001916822 0.007905382
-##  (between_SS / total_SS =  88.6 %)
-## 
-## Available components:
-## 
-## [1] "cluster"      "centers"      "totss"        "withinss"    
-## [5] "tot.withinss" "betweenss"    "size"         "iter"        
-## [9] "ifault"
-
-
-

mshapes: Mean shapes

-

We can retrieve the mean shapes, group wise (if a fac is specified), or the global mean shape (if omitted). It works from the Coe object:

-
# mean shape
-bot.f %>% mshapes() %>% coo_plot()
-

-
# mean shape, per group
-bot.ms <- mshapes(bot.f, 1)
-beer   <- bot.ms$shp$beer    %T>% coo_plot(border="blue")
-whisky <- bot.ms$shp$whisky  %T>% coo_draw(border="red")
-legend("topright", lwd=1,
-       col=c("blue", "red"), legend=c("beer", "whisky"))
-

-
## * no 'fac' provided. Returns meanshape.
-
-
-
-

Manipulating objects

-
-

dplyr verbs

-

One common yet boring task of morphometrics consists in handling datasets: add new information, remove some individuals, etc.

-

Momocs adapts dplyr verbs to its objects, and add new ones. If you have never heard of dplyr, let’s have a look to this introduction, this may change your (R) life.

-

Basics verbs are implemented; try the following:

-
data(olea)
-olea
-
## An Opn object with: 
-## --------------------
-##  - $coo: 210 open outlines (99 +/- 4 coordinates)
-##  - $fac: 4 classifiers:
-##      'var' (factor 4): Aglan, Cypre, MouBo1, PicMa.
-##      'domes' (factor 2): cult, wild.
-##      'view' (factor 2): VD, VL.
-##      'ind' (factor 30): O1, O10, O11, O12, O13, O14, O15, O16, O17, O18, O19 ... + 19 more.
-
# slice: select individuals based on their position
-slice(olea, 1:5)
-
## An Opn object with: 
-## --------------------
-##  - $coo: 5 open outlines (99 +/- 4 coordinates)
-##  - $fac: 4 classifiers:
-##      'var' (factor 4): Aglan, Cypre, MouBo1, PicMa.
-##      'domes' (factor 2): cult, wild.
-##      'view' (factor 2): VD, VL.
-##      'ind' (factor 30): O1, O10, O11, O12, O13, O14, O15, O16, O17, O18, O19 ... + 19 more.
-
slice(olea, -(1:100))
-
## An Opn object with: 
-## --------------------
-##  - $coo: 110 open outlines (99 +/- 4 coordinates)
-##  - $fac: 4 classifiers:
-##      'var' (factor 4): Aglan, Cypre, MouBo1, PicMa.
-##      'domes' (factor 2): cult, wild.
-##      'view' (factor 2): VD, VL.
-##      'ind' (factor 30): O1, O10, O11, O12, O13, O14, O15, O16, O17, O18, O19 ... + 19 more.
-
# filter: select individual based on a logical condition
-filter(olea, domes=="cult", view!="VD")
-
## An Opn object with: 
-## --------------------
-##  - $coo: 60 open outlines (97 +/- 4 coordinates)
-##  - $fac: 4 classifiers:
-##      'var' (factor 4): Aglan, Cypre, MouBo1, PicMa.
-##      'domes' (factor 2): cult, wild.
-##      'view' (factor 2): VD, VL.
-##      'ind' (factor 30): O1, O10, O11, O12, O13, O14, O15, O16, O17, O18, O19 ... + 19 more.
-
# select: pick, reorder columns from the $fac
-select(olea, 1, Ind=ind)
-
## An Opn object with: 
-## --------------------
-##  - $coo: 210 open outlines (99 +/- 4 coordinates)
-##  - $fac: 2 classifiers:
-##      'var' (factor 4): Aglan, Cypre, MouBo1, PicMa.
-##      'Ind' (factor 30): O1, O10, O11, O12, O13, O14, O15, O16, O17, O18, O19 ... + 19 more.
-
# rename: rename columns (select can also do it)
-rename(olea, domesticated=domes)
-
## An Opn object with: 
-## --------------------
-##  - $coo: 210 open outlines (99 +/- 4 coordinates)
-##  - $fac: 4 classifiers:
-##      'var' (factor 4): Aglan, Cypre, MouBo1, PicMa.
-##      'domesticated' (factor 2): cult, wild.
-##      'view' (factor 2): VD, VL.
-##      'ind' (factor 30): O1, O10, O11, O12, O13, O14, O15, O16, O17, O18, O19 ... + 19 more.
-
# mutate: add new columns
-mutate(olea, fake=factor(rep(letters[1:2], each=105)))
-
## An Opn object with: 
-## --------------------
-##  - $coo: 210 open outlines (99 +/- 4 coordinates)
-##  - $fac: 5 classifiers:
-##      'var' (factor 4): Aglan, Cypre, MouBo1, PicMa.
-##      'domes' (factor 2): cult, wild.
-##      'view' (factor 2): VD, VL.
-##      'ind' (factor 30): O1, O10, O11, O12, O13, O14, O15, O16, O17, O18, O19 ... + 19 more.
-##      'fake' (factor 2): a, b.
-
# transmute: add new columns and drop others
-transmute(olea, fake=factor(rep(letters[1:2], each=105)))
-
## An Opn object with: 
-## --------------------
-##  - $coo: 210 open outlines (99 +/- 4 coordinates)
-##  - $fac: 1 classifier:
-##      'fake' (factor 2): a, b.
-

And you can pipe those operations: say, we only want dorsal views from domesticated individuals, for a (renamed) ‘status’ column, and drop the ‘ind’ column:

-
olea %>% 
-filter(domes=="cult", view=="VD") %>% 
-rename(domesticated=domes) %>% 
-select(-ind)
-
## An Opn object with: 
-## --------------------
-##  - $coo: 90 open outlines (100 +/- 2 coordinates)
-##  - $fac: 3 classifiers:
-##      'var' (factor 4): Aglan, Cypre, MouBo1, PicMa.
-##      'domesticated' (factor 2): cult, wild.
-##      'view' (factor 2): VD, VL.
-

This should save some headaches.

-
-
-

New verbs ala dplyr

-

New verbs are implemented: for instance, you can chop (a rougher slicing) according to a condition: this will create a list, on which you can apply further operations, then combine it back. This is particularly useful when you want to apply independant treatments to different partitions, eg orthogonal views of your model. Prior to this, we can use table to cross-tabulate data from $fac. We could have done the first step of what follows with rm_uncomplete that drops (if any) missing data.

-
table(olea, "view", "var") 
-# we drop 'Cypre' since there is no VL for 'Cypre' var
-olea %>% filter(var != "Cypre") %>%              
-  # split, do morphometrics, combine
-  chop(view) %>% lapply(opoly) %>% combine() %>% 
-  # note the two views in the morphospace
-  PCA() %>% plot("var")
-

-
##     var
-## view Aglan Cypre MouBo1 PicMa
-##   VD    30    30     30    30
-##   VL    30     0     30    30
-##  * 'nb.pts' missing and set to:  91 
-##  * 'degree' missing and set to:  5 
-##  * 'nb.pts' missing and set to:  91 
-##  * 'degree' missing and set to:  5
-
-
-

Various helpers

-

Some methods help, on Coe objects to:

-
    -
  • sample a given number: sample_n;
  • -
  • sample a given proportion: sample_frac;
  • -
  • generate new individuals based on calibrated Gaussian coefficient generation: breed;
  • -
  • generate new individuals based on permutations: perm.
  • -
-

Several shortcuts are implemented on Coo and Coe objects: * names returns shape names; * length returns their number; * table cross-tabulates the$fac component; * Ntable does the same job and plots a confusion matrix; * [] extracts one (or more) shape; * $ can access either a shape name or a column name for the $fac.

-

Try the following:

-
names(bot)
-length(bot)
-table(olea, "var", "domes")
-Ntable(olea, "var", "domes")
-bot[1]
-bot[1:5]
-bot$brahma
-bot$type
-
-
-
-

Babel import/export

-

There are various morphometrics formats in the wild, almost as much as softwares. Momocs tries to create bridges between them, all gathered in the Babel family.

-
-

Within R

-

You can convert from/to array, matrix, list or data.frame with the functions {a, m, l, d}2{a, m, l, d}. For instance, l2a converts a list into an array that you can use with geomorph; a2l does the inverse operation

-

Imagine you want to import pupfish from geomorph as a Ldk object:

-
library(geomorph)
-data(pupfish)
-str(pupfish)
-# so $coords will become $coo, and
-# all other components will be turned into a data.frame to feed $fac
-# with a single line
-Ldk(coo=pupfish$coords %>% a2l,
-fac=pupfish[-1] %>% as.data.frame())
-
-
-

Import from StereoMorph

-

If you use this excellent package by Olsen to digitize landmarks and curves, you can import them, from the files produced with the functions import_StereoMorph_ldk and import_StereoMorph_curve.

-
-
-

Import from tps and other digitizing softwares

-
    -
  • .tps files can be read with import_tps
  • -
  • .nts files an be read with nts2Coo (will be turned into import_nts soon)
  • -
-
-
-

Import misc

-
    -
  • If covariables are encoded in filenames, which is a good practice, eg if you have files named spA_group7_ind4_VL.{txt|jpg|etc.}, use lf_structure;
  • -
  • If you need rewriting rules on your $fac, rw_rule is your friend;
  • -
  • If you need to rescale imported coordinates, see rescale;
  • -
  • If you need to tie images (eg outlines) and .txt (eg coordinates of landmarks on them), see tie_jpg_txt.
  • -
-
-
-

Save from R

-

The best way to save a Momocs object is probably to use the base save function. You can call it back afterwards with load:

-
save(bot, file="Bottles.rda")
-# closing R, going to the beach, back at work
-load("Bottles.rda") # bot is back
-
-
-

Export from R

-

Any Momocs object, Coos, Coes, PCAs, etc. can be turned into a data.frame with as_df. Work with dplyr, ggplot2 is made easy and you can export it as .txt, .csv “by hand” or use the export function:

-
bot %>% as_df # then %>% write.table
-bot %>% efourier %>% export
-bot %>% efourier %>% PCA %>% export
-

But, of course, you can directly access information within the Momocs objects; try the following:

-
# from Coo objects
-bot$coo
-bot$fac
-
-# from Coe objects
-bot.f$coe
-bot.f$fac
-as_df(bot.f)
-
-# from PCA objects
-bot.p$x # scores
-bot.p$rotation # rotation matrix
-
-
-
-

Graphics

-

The most common graphics have been already presented in previous sections. But there are many more of them, and they are gathered in the Graphics family that can be accessed with … TODO.

-
-

tps_*: Thin Plate Splines

-

TPS have not been presented before but here there are:

-
tps_grid(beer, whisky)
-tps_arr(beer, whisky)
-tps_iso(beer, whisky)
-

Again, plenty options in ?tps_*.

-
-
-

ggplot2

-

Many graphical function have their ggplot2 counterpart:

-
panel(bot)
-

-
panel2(bot)
-

-

And the classical ggplot2 grammar applies:

-
library(ggplot2)
-gg <- panel2(bot)
-gg + theme_minimal()
-

-

Otherwise, you can build your own plots. Let’s begin with a simple example:

-
# we build a ggplot object from a shape turned into a data.frame
-shapes[4] %>% m2d() %>% ggplot() + 
-  aes(x, y) + geom_path() + coord_equal() + 
-  labs(title="ggplot2 Meow") + theme_minimal()
-

-

Here is a more complicated plot that takes profit of as_df methods that turns objects into ggplot2-friendly data.frames:

-
bot.p %>% as_df() %>% ggplot() +
-  aes(x=PC1, y=PC2, col=type) + coord_equal() + 
-  geom_point() + geom_density2d() + theme_light()
-

-
-
-

Color palettes

-
    -
  • Nice palettes are bundled with Momocs, see ?Palettes.
  • -
  • Overall, RColorBrewer is more than an option if you work with colors.
  • -
-
-
-
-

Frequently asked questions

- -
- -
- - - - - - - -