sizeMat: An R Package to Estimate Size at Sexual Maturity

Josymar Torrejon-Magallanes

2026-05-29

Introduction

The sizeMat package estimates size at sexual maturity in organisms, especially fish and invertebrates.

It includes tools for estimating:

The size at sexual maturity is defined here as the length at which a randomly chosen individual has a 50% probability of being mature.

Installation

The stable version can be installed from CRAN:

install.packages("sizeMat")

The development version can be installed from GitHub:

# install.packages("devtools")
devtools::install_github("ejosymart/sizeMat")

1. Size at morphometric maturity

Morphometric maturity is estimated from the relative growth relationship between two allometric variables.

In this example, we use the crabdata dataset. This dataset contains allometric measurements and biological information for crabs of the species Chionoecetes tanneri.

data(crabdata)

head(crabdata)
#>   year month carapace_width carapace_length chela_height chela_width
#> 1 1974     1            106             107         14.0          22
#> 2 1974     1            129             129         27.0          44
#> 3 1974     1            119             122         14.6          23
#> 4 1974     1            115             118         18.6          29
#> 5 1974     1             97              97         11.0          17
#> 6 1974     1             94              96         10.0          15
#>   sex_category
#> 1            m
#> 2            m
#> 3            m
#> 4            m
#> 5            m
#> 6            m
names(crabdata)
#> [1] "year"            "month"           "carapace_width"  "carapace_length"
#> [5] "chela_height"    "chela_width"     "sex_category"

1.1 Classification of juveniles and adults

The function classify_mature() classifies individuals into two groups:

The classification is based on a principal components analysis using two allometric variables, followed by hierarchical clustering and discriminant analysis.

The argument varNames requires two allometric variables. The first variable is treated as the independent variable and the second as the dependent variable. The argument varSex identifies the sex variable. If selectSex = NULL, all individuals are used.

classify_data <- classify_mature(
  crabdata,
  varNames = c("carapace_width", "chela_height"),
  varSex = "sex_category",
  selectSex = NULL,
  method = "ld"
)
#> all individuals were used in the analysis

classify_data_males <- classify_mature(
  crabdata,
  varNames = c("carapace_width", "chela_height"),
  varSex = "sex_category",
  selectSex = "m",
  method = "ld"
)
#> only m-sex were used in the analysis

print(classify_data)
#> Number in juvenile group = 83 
#> 
#> Number in adult group = 140 
#> 
#> -------------------------------------------------------- 
#> 1) Linear regression for juveniles 
#> 
#> Call:
#> glm(formula = y ~ x, data = juv)
#> 
#> Coefficients:
#>              Estimate Std. Error t value Pr(>|t|)    
#> (Intercept) -3.794687   0.497056  -7.634 3.93e-11 ***
#> x            0.161327   0.004701  34.314  < 2e-16 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> (Dispersion parameter for gaussian family taken to be 0.7320842)
#> 
#>     Null deviance: 921.306  on 82  degrees of freedom
#> Residual deviance:  59.299  on 81  degrees of freedom
#> AIC: 213.63
#> 
#> Number of Fisher Scoring iterations: 2
#> 
#> -------------------------------------------------------- 
#> 2) Linear regression for adults 
#> 
#> Call:
#> glm(formula = y ~ x, data = adt)
#> 
#> Coefficients:
#>               Estimate Std. Error t value Pr(>|t|)    
#> (Intercept) -11.246726   1.199496  -9.376   <2e-16 ***
#> x             0.273837   0.008648  31.663   <2e-16 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> 
#> (Dispersion parameter for gaussian family taken to be 2.265729)
#> 
#>     Null deviance: 2584.24  on 139  degrees of freedom
#> Residual deviance:  312.67  on 138  degrees of freedom
#> AIC: 515.79
#> 
#> Number of Fisher Scoring iterations: 2
#> 
#> -------------------------------------------------------- 
#> 3) Difference between slopes (ANCOVA) 
#>               Estimate  Std. Error   t value     Pr(>|t|)
#> (Intercept) -3.7946869 0.757105677 -5.012097 1.109526e-06
#> x            0.1613275 0.007161179 22.528064 6.035478e-59
#> mature      -7.4520389 1.285219562 -5.798261 2.320729e-08
#> x:mature     0.1125093 0.010361046 10.858878 2.956242e-22
#> [1] "slopes are different"

1.2 Base graphics plot for classified data

By default, plot.classify() uses base R graphics.

plot(
  classify_data,
  xlab = "Carapace width (mm)",
  ylab = "Chela height (mm)"
)

The graphic can be customized using colors, point symbols, line types, and point size.

plot(
  classify_data,
  xlab = "Carapace width (mm)",
  ylab = "Chela height (mm)",
  col = c(2, 3),
  pch = c(5, 6),
  lty_lines = c(1, 2),
  lwd_lines = c(1, 3),
  cex = c(1, 2),
  main = "Classification"
)

1.3 ggplot2-style plot for classified data

A ggplot2 style can be obtained with gg_style = TRUE.

plot(
  classify_data,
  xlab = "Carapace width (mm)",
  ylab = "Chela height (mm)",
  col = c("steelblue", "firebrick"),
  pch = c(16, 17),
  gg_style = TRUE
)

Because the function returns a ggplot object when gg_style = TRUE, the plot can be further modified.

p_classify <- plot(
  classify_data,
  xlab = "Carapace width (mm)",
  ylab = "Chela height (mm)",
  col = c("steelblue", "firebrick"),
  pch = c(16, 17),
  gg_style = TRUE
)

p_classify + ggplot2::theme_bw()

2. Estimation of size at morphometric maturity

After individuals are classified, size at morphometric maturity can be estimated using morph_mature().

The model is based on a logistic function:

\[ P_{CS} = \frac{1}{1 + e^{-(\hat{\beta}_{0} + \hat{\beta}_{1}X)}} \]

where \(P_{CS}\) is the probability of being mature at length \(X\).

The size at 50% maturity is calculated as:

\[ L_{50} = -\frac{\hat{\beta}_{0}}{\hat{\beta}_{1}} \]

The argument method defines the model type:

For vignette purposes, we use a relatively small number of iterations so that the document compiles quickly.

set.seed(123)

my_morph_fq <- morph_mature(
  classify_data,
  method = "fq",
  niter = 200
)

print(my_morph_fq)
#> formula: Y = 1/1+exp-(A + B*X)
#>     Original Bootstrap (Median)
#> A   -20.753  -21.086           
#> B   0.1748   0.1762            
#> L50 118.7237 118.6442          
#> R2  0.7111   -

my_morph_bayes <- morph_mature(
  classify_data,
  method = "bayes",
  niter = 200
)

print(my_morph_bayes)
#> formula: Y = 1/1+exp-(A + B*X)
#>     Bootstrap (Median)
#> A             -20.3108
#> B               0.1724
#> L50           118.3878
#> R2              0.7111

2.1 Base graphics plot for morphometric maturity

By default, plot.morphMat() uses base R graphics. It produces histograms for the model parameters and the maturity ogive.

oldpar <- par(no.readonly = TRUE)
par(mfrow = c(2, 2))

plot(
  my_morph_fq,
  xlab = "Carapace width (mm)",
  ylab = "Proportion mature",
  col = c("blue", "red")
)

#> Size at morphometric maturity = 118.6 
#> Confidence intervals = 116 - 121 
#> Rsquare = 0.71

par(oldpar)

To plot only the maturity ogive, use onlyOgive = TRUE.

plot(
  my_morph_fq,
  xlab = "Carapace width (mm)",
  ylab = "Proportion mature",
  col = c("blue", "red"),
  onlyOgive = TRUE
)

#> Size at morphometric maturity = 118.6 
#> Confidence intervals = 116 - 121 
#> Rsquare = 0.71

2.2 ggplot2-style plots for morphometric maturity

A ggplot2 maturity ogive can be obtained using gg_style = TRUE.

plot(
  my_morph_fq,
  xlab = "Carapace width (mm)",
  ylab = "Proportion mature",
  col = c("steelblue", "firebrick"),
  onlyOgive = TRUE,
  gg_style = TRUE
)
#> Size at morphometric maturity = 118.6 
#> Confidence intervals = 116 - 121 
#> Rsquare = 0.71

When onlyOgive = FALSE and gg_style = TRUE, the function returns a list of independent ggplot objects.

p_morph <- plot(
  my_morph_fq,
  xlab = "Carapace width (mm)",
  ylab = "Proportion mature",
  col = c("steelblue", "firebrick"),
  gg_style = TRUE
)
#> Size at morphometric maturity = 118.6 
#> Confidence intervals = 116 - 121 
#> Rsquare = 0.71

names(p_morph)
#> [1] "A"     "B"     "L50"   "ogive"

The individual plots can then be displayed separately.

p_morph$A

p_morph$B

p_morph$L50

p_morph$ogive

The returned plots can also be modified using standard ggplot2 syntax.

p_morph$ogive +
  ggplot2::theme_bw()

3. Size at gonadal maturity

Gonadal maturity is estimated using a maturity stage variable and an allometric variable such as total length.

In this example, we use the matFish dataset.

data(matFish)

head(matFish)
#>   total_length stage_mat
#> 1           12         I
#> 2           12         I
#> 3           13         I
#> 4           14         I
#> 5           14         I
#> 6           14         I

The dataset contains:

In this example, stage I is considered immature, whereas stages II, III, and IV are considered mature.

3.1 Estimation of size at gonadal maturity

The function gonad_mature() requires:

set.seed(123)

my_gonad_fq <- gonad_mature(
  matFish,
  varNames = c("total_length", "stage_mat"),
  immName = "I",
  matName = c("II", "III", "IV"),
  method = "fq",
  niter = 200
)

print(my_gonad_fq)
#> formula: Y = 1/[1+exp-(A + B*X)]
#>     Original Bootstrap (Median)
#> A   -8.6047  -8.6497           
#> B   0.356    0.3578            
#> L50 24.1694  24.1841           
#> R2  0.5595   -

my_gonad_bayes <- gonad_mature(
  matFish,
  varNames = c("total_length", "stage_mat"),
  immName = "I",
  matName = c("II", "III", "IV"),
  method = "bayes",
  niter = 200
)

print(my_gonad_bayes)
#> formula: Y = 1/[1+exp-(A + B*X)]
#>     Bootstrap (Median)
#> A              -8.6026
#> B               0.3565
#> L50            24.1457
#> R2              0.5595

3.2 Base graphics plot for gonadal maturity

By default, plot.gonadMat() uses base R graphics.

oldpar <- par(no.readonly = TRUE)
par(mfrow = c(2, 2))

plot(
  my_gonad_fq,
  xlab = "Total length (cm)",
  ylab = "Proportion mature",
  col = c("blue", "red")
)

#> Size at gonadal maturity = 24.2 
#> Confidence intervals = 23.8 - 24.6 
#> Rsquare = 0.56

par(oldpar)

To plot only the maturity ogive, use onlyOgive = TRUE.

plot(
  my_gonad_fq,
  xlab = "Total length (cm)",
  ylab = "Proportion mature",
  col = c("blue", "red"),
  onlyOgive = TRUE
)

#> Size at gonadal maturity = 24.2 
#> Confidence intervals = 23.8 - 24.6 
#> Rsquare = 0.56

The legend position can be modified with legendPosition.

plot(
  my_gonad_fq,
  xlab = "Total length (cm)",
  ylab = "Proportion mature",
  col = c("blue", "red"),
  onlyOgive = TRUE,
  legendPosition = "bottomright"
)

#> Size at gonadal maturity = 24.2 
#> Confidence intervals = 23.8 - 24.6 
#> Rsquare = 0.56

The legend can also be removed.

plot(
  my_gonad_fq,
  xlab = "Total length (cm)",
  ylab = "Proportion mature",
  col = c("blue", "red"),
  onlyOgive = TRUE,
  showLegend = FALSE
)

#> Size at gonadal maturity = 24.2 
#> Confidence intervals = 23.8 - 24.6 
#> Rsquare = 0.56

3.3 ggplot2-style plots for gonadal maturity

A ggplot2 maturity ogive can be obtained using gg_style = TRUE.

plot(
  my_gonad_fq,
  xlab = "Total length (cm)",
  ylab = "Proportion mature",
  col = c("steelblue", "firebrick"),
  onlyOgive = TRUE,
  gg_style = TRUE
)
#> Size at gonadal maturity = 24.2 
#> Confidence intervals = 23.8 - 24.6 
#> Rsquare = 0.56

The position of the \(L_{50}\) and \(R^2\) labels can also be changed.

plot(
  my_gonad_fq,
  xlab = "Total length (cm)",
  ylab = "Proportion mature",
  col = c("steelblue", "firebrick"),
  onlyOgive = TRUE,
  gg_style = TRUE,
  legendPosition = "bottomright"
)
#> Size at gonadal maturity = 24.2 
#> Confidence intervals = 23.8 - 24.6 
#> Rsquare = 0.56

When onlyOgive = FALSE and gg_style = TRUE, the function returns a list of independent ggplot objects.

p_gonad <- plot(
  my_gonad_fq,
  xlab = "Total length (cm)",
  ylab = "Proportion mature",
  col = c("steelblue", "firebrick"),
  gg_style = TRUE
)
#> Size at gonadal maturity = 24.2 
#> Confidence intervals = 23.8 - 24.6 
#> Rsquare = 0.56

names(p_gonad)
#> [1] "A"     "B"     "L50"   "ogive"

The individual plots can be displayed separately.

p_gonad$A

p_gonad$B

p_gonad$L50

p_gonad$ogive

The returned plots can be customized using ggplot2.

p_gonad$ogive +
  ggplot2::theme_bw()

References

Agostinho, C. S. (2000). Use of otoliths to estimate size at sexual maturity in fish. Brazilian Archives of Biology and Technology, 43(4).

Corgos, A. and Freire, J. (2006). Morphometric and gonad maturity in the spider crab Maja brachydactyla: a comparison of methods for estimating size at maturity in species with determinate growth. ICES Journal of Marine Science, 63(5), 851-859.

Roa, R., Ernst, B. and Tapia, F. (1999). Estimation of size at sexual maturity: an evaluation of analytical and resampling procedures. Fishery Bulletin, 97(3), 570-580.

Somerton, D. A. (1980). A computer technique for estimating the size of sexual maturity in crabs. Canadian Journal of Fisheries and Aquatic Sciences, 37(10), 1488-1494.