knitr::opts_chunk$set(echo = TRUE)
In Momocs, a shape is a matrix of (x, y)
coordinates. When they are plenty, they are usually gathered in a Coo
object which is, essentially, a list with at least a $coo
component.
library(Momocs)
# a single shape bot[1] %>% is_shp() # tests if it is a 2-col matrix without NAs bot[1] %>% head() # a collection of shapes bot %>% class() # Out for outlines, but also a Coo. See ?Coo bot %>% is.list() # essentially a list bot$coo %>% class() # with a $coo component bot$coo[1:2] %>% lapply(head) # where shapes are gathered
Most operations on shapes can also be done on Coo
objects. For example, getting the area or centering:
coo_area(bot[1]) # in pixels^2 coo_area(bot) %>% head()
In other words most coo_
functions are actually methods that can actually be passed with a single matrix or a Coo object.
Below, we will distinguish coo_*
operations based on whether they return a shape (eg if it is a geometric operation) or a scalar (a single number that can be used as a shape descriptor).
Not all are described but you can obtain a full list of coo_
operations with:
cool <- apropos("coo_") # get the full list head(cool) # the firt 6 length(cool) # how many are defined
coo_scalar
calculate all scalar descriptors included in Momocs. coo_rectilinearity
is not included by default since it takes a looot of time to compute.
df <- shapes %>% coo_scalars() df
Each of the function listed below has its own method that you can used by prefixing it with coo_
; see the example below with coo_area
.
colnames(df) %>% cat(sep="\n") coo_area(shapes[4]) # in pixels^2 coo_area(shapes) # a subset dplyr::tibble(area=coo_area(shapes), perim=coo_perim(shapes)) %>% head()
The functions below return shapes, so we exemplify them with graphs. For the sake of clarity/speed we illustrate them on single shape but, again, this can be done on Coo
objects.
# A single example on Coo bot %>% stack bot %>% coo_center %>% stack()
Now we go with a cat and we will extensively use coo_plot
. We define a function that will help display side by side the original and transformed cat; when I use p(coo_align)
, it is equivalent to coo_align(your_shp)
or shp %>% coo_align
shp <- shapes[4] shp %>% coo_plot()
# from a shape (shp) in the global environment (do not tell anyone !) # apply a transformation (fun) and plot the two, side by side p <- function(fun){ title <- as.character(match.call()$fun) # capture the function name par(mfrow=c(1, 2)) # side by side plots shp %>% coo_plot() # original shape shp %>% fun %>% coo_plot(main=title) # transform and plot par(mfrow=c(1, 1)) # back to original layout }
shp %>% coo_plot(main="original cat") # scaling shp %>% coo_scale %>% coo_plot(main="coo_scale") # templating shp %>% coo_template(1) %>% coo_plot(ylim=c(-1, 1), main="coo_template"); rect(-0.5, -0.5, 0.5, 0.5)
shp %>% coo_scalex(2) %>% coo_plot(main="coo_scalex") shp %>% coo_scaley(3) %>% coo_plot(main="coo_scaley") shp %>% coo_shearx(1) %>% coo_plot(main="coo_shearx") shp %>% coo_sheary(1) %>% coo_plot(main="coo_sheary")
shp %>% coo_align %>% coo_plot(main="coo_align") shp %>% coo_aligncalliper %>% coo_plot(main="coo_aligncalliper") shp %>% coo_alignminradius %>% coo_plot(main="coo_alignminradius") shp %>% coo_alignxax %>% coo_plot(main="coo_alignxax")
# we use points with id 93 and 516 as landmarks coo_bookstein(shp, 93, 516) %>% coo_plot(main="coo_bookstein") # see coo_baseline for a more generic version
shp %>% coo_center %>% coo_plot(main="coo_center") # or coo_centre if you come from UK shp %>% coo_center %>% coo_trans(x= 5) %>% coo_plot(main="coo_trans") shp %>% coo_center %>% coo_trans(y= -2) %>% coo_plot(main="coo_trans")
shp %>% coo_rotate(pi/2) %>% coo_plot(main="coo_rotate(pi/2)") shp %>% coo_rotatecenter(-pi/6, center=c(250, 195)) %>% coo_plot(main="coo_rotatecenter") # with center ~on cat's nose # mirrorring shp %>% coo_flipx %>% coo_plot(main="coo_flipx") shp %>% coo_flipy %>% coo_plot(main="coo_flipy")
shp %>% coo_nb() shp %>% coo_sample(36) %>% coo_plot(main="coo_sample") shp %>% coo_sample_prop(1/20) %>% coo_plot(main="coo_sample") shp %>% coo_samplerr(36) %>% coo_plot(main="coo_samplerr") # regular radius shp %>% coo_sample(36) %>% coo_interpolate(144) %>% coo_plot(points=TRUE, main="coo_interpolate")
shp %>% coo_sample(24) %>% coo_plot(main="a cubist cat") shp %>% coo_sample(24) %>% coo_smooth(2) %>% coo_plot(main="coo_smooth")
If you have curves, you may prefer not to change first and last points:
olea[1] %>% coo_plot() olea[1] %>% coo_smooth(12) %>% coo_plot(main="coo_smooth") olea[1] %>% coo_smoothcurve(12) %>% coo_plot(main="coo_smoothcurve")
shp %>% coo_center %>% coo_plot(main="centered cat") shp %>% coo_center %>% coo_up() %>% coo_plot(main="coo_up") shp %>% coo_center %>% coo_down() %>% coo_plot(main="coo_down") shp %>% coo_center %>% coo_left() %>% coo_plot(main="coo_left") shp %>% coo_center %>% coo_right() %>% coo_plot(main="coo_right")
If you want to slice but want the first point to be on one end, then coo_slidegap
is your friend :
shp %>% coo_center %>% coo_right() %>% coo_slidegap %>% coo_plot(main="coo_right")
coo_slice
results in at least two shapes. Should be more useful with the argument ldk
and within a Coo
.
shp %>% coo_center %>% coo_slice(ids=c(93, 516)) %>% Opn %>% panel()
shp %>% coo_plot(main="original cat", cex.first.point = 2) shp %>% coo_slide(id=93) %>% coo_plot(main="coo_slide", cex.first.point = 2) # same comment for ldk/Coo as for coo_slice shp %>% coo_slidedirection("right") %>% coo_plot(main="coo_slidedirection", cex.first.point = 2)
shp12 <- shp %>% coo_sample(12) shp12 %>% coo_plot(main="a cubist cat") shp12 %>% coo_close %>% coo_plot(main="coo_close") shp12 %>% coo_close %>% coo_unclose %>% coo_plot(main="coo_unclose")
shp12 %>% coo_trimtop(3) %>% coo_plot(main="coo_trimtop") shp12 %>% coo_trimbottom(3) %>% coo_plot(main="coo_trimtop") shp12 %>% coo_trim(3) %>% coo_plot(main="coo_trim") shp %>% coo_extract(93:516) %>% coo_plot(main="coo_extract")
shp12 %>% coo_rev %>% coo_plot(main="coo_rev", cex.first.point = 2)
A side effect of coo_dxy
is to set the first point on (0, 0)
shp %>% coo_dxy %>% coo_plot(main="coo_dxy", cex.first.point = 2)
coo_force2close
can be use to spread differences between the first and last point, and to force closing:
shp %>% coo_center %>% coo_up %>% coo_plot(main="half a cat") shp %>% coo_center %>% coo_up %>% coo_force2close %>% coo_plot(main="stop animal cruelty now")
# for the sake of reproducibility set.seed(123) shp %>% coo_jitter(factor=10) %>% coo_plot(main="coo_jitter")
# coo_descriptors along coo_centdist coo_perimcum coo_perimpts # coo_descriptors non-scalars coo_boundingbox coo_centpos # should be a df? coo_chull coo_chull_onion coo_diffrange # coo_range_diff coo_lw coo_truss coo_range coo_range_enlarge # coo_drawers coo_arrows coo_draw coo_draw_rads coo_listpanel coo_lolli coo_oscillo # deprecate for a proper oscillo coo_plot coo_ruban # coo_others coo_angle_edges coo_angle_tangent coo_intersect_angle coo_intersect_direction coo_intersect_segment # coo_testers coo_is_closed coo_likely_anticlockwise coo_likely_clockwise # helpers coo_check coo_nb coo_ldk
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.