This page is restricted.
Please enter the access password.
Three R packages developed within the FunTraits toolkit for trait-based ecology of freshwater fish: from field photographs to landmarks, morphological traits, intraspecific variability and the global FISHMORPH morphospace. Click a package for its presentation page.
FishInTrait
in developmentField-campaign management for trait digitization: photographs, specimens, determinations and provenance journal.
intraitR
v1.35.0 · GitHubMorphological trait analysis toolkit for freshwater fish — landmarks, Procrustes, ratios, shape and trait spaces, intraspecific variability and measurement error.
Rfishmorph
v0.13.1 · GitHubDigitizing, storing, analysing and exploring the FISHMORPH database (Brosse et al. 2021): 21 landmarks, 11 segments, 9 ratios.
The three packages share the same object classes (intrait_landmarks is accepted
throughout) and the same FISHMORPH conventions, so a survey digitized with FishInTrait can be analysed with intraitR
and projected into — or added to — the FISHMORPH database with Rfishmorph. intraitR imports
Rfishmorph; both build on geomorph for geometric morphometrics.
# install.packages("remotes")
install.packages("geomorph")
remotes::install_github("FunTraits/Rfishmorph")
remotes::install_github("FunTraits/intraitR") # pulls Rfishmorph automatically
If you join a digitization campaign with me, you work on a folder of prepared photographs (one specimen per file, exported from the campaign project with FishInTrait; the file name is the specimen code and must not be changed). Install the packages as above, then follow the three steps below. Photographs never leave your computer: only their file name and pixel size are recorded.
The prepared photographs are shared in
this OneDrive folder. Open the link, select
only the folder you are working on and click Download (no account needed; OneDrive
delivers it as a .zip). Unzip it and put the photographs in the prepared/ folder of
your working directory (step 2).
Do not rename the photographs, not even to fix a typo or remove a space: the file name is the specimen code, and it is what links your measurements to the specimen, its species determination and the campaign project. If a name looks wrong, tell me rather than changing it.
Create a working folder with the photographs in prepared/ and launch the digitizer. From a few
calibration clicks, the ml-morph predictor proposes the 19 FISHMORPH landmarks; review every point, place the
scale bar (landmarks 20–21, length in mm asked by the app), score the quality and save. Everything is written
to one workbook and to an append-only journal that survives a crash.
Not comfortable with R? The pipeline app opens this same digitizer in your browser and hands you the same workbook and journal to send back — no installation at all.
library(intraitR)
digitize_landmarks(
photo_dir = "prepared", # the photographs I gave you
xlsx_path = "measurements/<Name>_landmarks.xlsx", # one workbook, 3 sheets
journal_dir = "journal", # source of truth, never edit
operator = "<your initials>",
mode = "new" # "correct" to review, "repeat" for repeatability
)
# Optional but recommended: digitize ~20 specimens 3 times blind for the
# measurement-error analysis (mode = "repeat" fills the "bias" sheet).
When you are done, send me a zip of the workbook and the journal/ folder
(the workbook alone is an export; the journal is what I merge into the campaign project
00_CampagneIntrait with consolidate_landmarks()). Please do not edit the workbook by hand,
do not rename photographs, and keep the same operator code from start to end.
Read the workbook back, check the landmarks on the photographs, correct the geometry, derive the FISHMORPH traits, then explore trait space, shape space, intraspecific variability and your own repeatability.
library(intraitR)
# ── read the measurements sheet (wide layout written by the digitizer) ────────
fish <- read_landmarks_xlsx("measurements/<Name>_landmarks.xlsx",
sheet = "measurements", n_landmarks = 23,
x_pattern = "{i}_X", y_pattern = "{i}_Y",
id_cols = "specimen")
# species come from the determinations table I give you (uid, species, ...),
# never from the file name: the specimen code SITE_YYYYMMDD_NNNN is an identity,
# the species a revisable hypothesis
det <- read.csv("determinations.csv")
uid <- sub("_i[0-9]+$", "", fish$metadata$specimen) # drop the _iK of plates
species <- det$species[match(uid, det$uid)]
# ── quality control ──────────────────────────────────────────────────────────
plot_fishmorph_points(fish, specimen = 1,
background_image = "prepared/<code>.jpg") # points on the photo
fish <- impute_landmarks(fish) # missing point (e.g. LM5) estimated
fish <- standardize_orientation(fish) # head left, belly down
fish <- correct_geometry(fish) # FISHMORPH digitizing conventions
detect_outliers(fish)
# ── FISHMORPH traits: 11 segments → 9 ratios ────────────────────────────────
seg <- fishmorph_segments(fish) # cm, via the scale bar
rat <- fishmorph_ratios(seg)
summary_traits(rat, groups = species)
# ── functional trait space of your sample ────────────────────────────────────
fts <- trait_space(rat, groups = species, na_action = "omit", remove_outliers = TRUE)
plot(fts) # spider / ellipse per species
plot(fts, style = "hull")
trait_disparity(rat, groups = species) # do species differ in trait dispersion?
# ── your specimens in the global FISHMORPH morphospace (9 556 species) ───────
proj <- project_fishmorph(rat, groups = species)
plot(proj, style = "hull") # density of the database + your species
plot(proj, style = "spider", itv_reference = TRUE)
# ── intraspecific variability ────────────────────────────────────────────────
itv <- itv_index(rat, groups = species) # inter- vs intraspecific variance
itv; plot(itv)
plot(itv_accumulation(rat, groups = species)) # how many individuals are enough?
# ── shape space (geometric morphometrics) ────────────────────────────────────
gpa <- gpa_fish(fishmorph_shape_landmarks(fish))
ss <- shape_space(gpa, groups = species)
plot(ss)
intraspecific_variability(gpa, groups = species, traits = rat)
# ── your repeatability (if you used mode = "repeat") ─────────────────────────
rep <- read_landmarks_xlsx("measurements/<Name>_landmarks.xlsx",
sheet = "bias", n_landmarks = 23,
x_pattern = "{i}_X", y_pattern = "{i}_Y",
id_cols = c("individual", "operator", "replicate"))
measurement_error(rep, individual = rep$metadata$individual)
plot(digitization_error(rep, individual = rep$metadata$individual)) # bias per landmark
demo("pipeline_T26_saudrune", package = "intraitR"), and the vignette
vignette("intraitR-intro") explains each function. Keep your analysis in a script
(or an R Markdown file) so that it can be re-run when I return the consolidated campaign data.
The whole workflow in a web application, for people who do not write R: measure the landmarks on your
photographs, check and correct them, compute the FISHMORPH traits, and get the figures (trait space, FISHMORPH
morphospace, intraspecific variability, shape space, repeatability) with every table and the R script that
reproduces them. Every computation is an intraitR function, and the measuring step
is the package's own digitizer — the application behind digitize_landmarks(),
served as it is, so it writes the same workbook and the same append-only journal.
See also: the R packages I rely on — an annotated catalogue of community packages for functional ecology, modelling, spatial analysis and visualisation.