Elliptical Fourier transforms

efourier(x, ...)

# S3 method for default
efourier(x, nb_h = NA, raw = FALSE, ...)

# S3 method for coo_single
efourier(x, nb_h = NA, raw = FALSE, ...)

# S3 method for coo_list
efourier(x, nb_h = NA, ...)

# S3 method for mom_tbl
efourier(x, nb_h = NA, keep_coo = FALSE, ...)

efourier_i(x, nb_h = NA, nb_pts = 120)

efourier_norm(x, ...)

# S3 method for default
efourier_norm(x, first_point = FALSE, raw = FALSE, ...)

# S3 method for coe_list
efourier_norm(x, first_point = FALSE, ...)

# S3 method for mom_tbl
efourier_norm(x, first_point = FALSE, ...)

Arguments

x

coo_single, coo_list or mom_tbl

...

for generics. Useless here.

nb_h

int nb of harmonics. Default to 6 for efourier, to all of them for efourier_i

raw

logical whether to return raw and full results for efourier and efourier_norm

keep_coo

logical whether to retain coo column

nb_pts

int nb of points for the reconstruction

first_point

logical whether to normalize for the first point using efourier_norm

Details

For the maths behind see the paper in JSS.

Normalization of coefficients has long been a matter of trouble, and not only for newcomers. There are two ways of normalizing outlines: the first, and by far the most used, is to use a "numerical" alignment, directly on the matrix of coefficients. The coefficients of the first harmonic are consumed by this process but harmonics of higher rank are normalized in terms of size and rotation. This is sometimes referred as using the "first ellipse", as the harmonics define an ellipse in the plane, and the first one is the mother of all ellipses, on which all others "roll" along. This approach is really convenient as it is done easily by most software (if not the only option) and by Momocs too. It is the default option of efourier.

But here is the pitfall: if your shapes are prone to bad aligments among all the first ellipses, this will result in poorly (or even not at all) "homologous" coefficients. The shapes particularly prone to this are either (at least roughly) circular and/or with a strong bilateral symmetry. Also, and perhaps more explicitely, morphospace usually show a mirroring symmetry, typically visible when calculated in some couple of components (usually the first two).

If you see these upside-down (or 180 degrees rotated) shapes on the morphospace, you should seriously consider aligning your shapes before the efourier step, and performing the latter with norm = FALSE.

You have several options to align your shapes, using control points (or landmarks), by far the most time consuming (and less reproducible) but possibly the best one too when alignment is too tricky to automate. You can also try Procrustes alignment (see fgProcrustes) (<- todo link 4 here) through their calliper length (see coo_aligncalliper), etc. You should also make the first point homologous either with coo_slide or coo_slidedirection to minimize any subsequent problems.

I will dedicate (some day) a vignette or a paper to this problem.

Functions

  • efourier_i: inverse efourier function

  • efourier_norm: efourier numerical normalization

References

Claude, J. (2008) Morphometrics with R, Use R! series, Springer 316 pp. Ferson S, Rohlf FJ, Koehn RK. 1985. Measuring shape variation of two-dimensional outlines. Systematic Biology 34: 59-68.

See also

Other morphometrics: dfourier(), npoly(), opoly()

Examples

bot %>% pick() %>% efourier(4) %>% print() %>% efourier_i()
#> # A tibble: 1 x 16 #> a1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4 d1 #> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> #> 1 -134. 8.42 20.8 -2.59 -19.3 -30.3 8.69 4.37 57.0 -3.16 -15.7 5.58 -441. #> # … with 3 more variables: d2 <dbl>, d3 <dbl>, d4 <dbl> #> ❯coe_single with 16 coefficients
#> # A tibble: 120 x 2 #> x y #> <dbl> <dbl> #> 1 0 0 #> 2 0 0 #> 3 0 0 #> 4 0 0 #> 5 0 0 #> 6 0 0 #> 7 0 0 #> 8 0 0 #> 9 0 0 #> 10 0 0 #> # … with 110 more rows #> ❯coo_single with 120 coordinates
bot$coo[1:2] %>% efourier(4) %>% print() %>% efourier_i() %>% class()
#> <list_of<coe_single<>>[2]> #> $brahma #> # A tibble: 1 x 16 #> a1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4 d1 #> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> #> 1 -143. 5.29 23.0 -11.4 -13.9 -21.9 11.4 13.6 64.4 -3.15 -18.0 5.76 -485. #> # … with 3 more variables: d2 <dbl>, d3 <dbl>, d4 <dbl> #> ❯coe_single with 16 coefficients #> #> $caney #> # A tibble: 1 x 16 #> a1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4 d1 #> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> #> 1 -134. 8.42 20.8 -2.59 -19.3 -30.3 8.69 4.37 57.0 -3.16 -15.7 5.58 -441. #> # … with 3 more variables: d2 <dbl>, d3 <dbl>, d4 <dbl> #> ❯coe_single with 16 coefficients #>
#> [1] "coo_list" "list" "vctrs_list_of" "vctrs_vctr" #> [5] "list"
bot[1:3, ] %>% efourier(4) %>% efourier_norm()
#> # A tibble: 3 x 3 #> type fake coe #> <fct> <fct> <list<coe_single[,0]>> #> 1 whisky a <tibble [1 × 16]> #> 2 whisky a <tibble [1 × 16]> #> 3 whisky a <tibble [1 × 16]> #> ❯mom_tbl