This document is for the course Fisheries Technology and Evaluation of Resources (Univ. Algarve).
Load needed libraries
library(ggplot2)
library(dplyr)
library(tidyr)
#-----------------------------------------------------------
# 1. Helper functions for selectivity curves
#-----------------------------------------------------------
# 1.1 Logistic selectivity
# Typical for trawl codend, increasing to an asymptote at 1
# Parameters:
# L50 = length at 50% retention
# SR = selection range = L75 - L25
logistic_sel <- function(L, L50, SR) {
# For the logistic curve:
# SR = 2*log(3) / b => b = 2*log(3) / SR
b <- 2 * log(3) / SR
a <- -b * L50
1 / (1 + exp(-(a + b * L)))
}
# 1.2 Normal dome-shaped selectivity
# Typical for gillnets/hooks: catches peak at an optimal size, then drop
# Parameters:
# mu = mode (peak length)
# sigma = spread (standard deviation)
normal_sel <- function(L, mu, sigma) {
s <- exp(-0.5 * ((L - mu) / sigma)^2)
s / max(s) # scale so max = 1 for easier comparison
}
# 1.3 Double-normal (bi-normal) dome-shaped selectivity
# More flexible dome-shaped form (can be skewed, bimodal, etc.)
# Parameters:
# mu1, sigma1 = first mode
# mu2, sigma2 = second mode
# w = weight of first mode (0–1)
double_normal_sel <- function(L, mu1, sigma1, mu2, sigma2, w = 0.5) {
s1 <- exp(-0.5 * ((L - mu1) / sigma1)^2)
s2 <- exp(-0.5 * ((L - mu2) / sigma2)^2)
s <- w * s1 + (1 - w) * s2
s / max(s) # scale so max = 1
}
# Length grid used for all plots
L_grid <- seq(20, 160, by = 1)
# Example 1: Different L50, same SR
# Imagine three codends with increasing L50 (selective for larger fish)
codends <- data.frame(
gear = c("Codend A", "Codend B", "Codend C"),
L50 = c(30, 40, 50), # increases
SR = c(8, 8, 8) # same SR
)
logistic_df <- codends |>
crossing(length = L_grid) |>
mutate(selectivity = logistic_sel(length, L50, SR))
ggplot(logistic_df, aes(x = length, y = selectivity, colour = gear)) +
geom_line(linewidth = 1.1) +
labs(
x = "Length (cm)",
y = "Retention probability",
colour = "Codend",
title = "Logistic selectivity – different L50, same SR"
) +
theme_minimal(base_size = 13)
# ----------------------------------------------------------
# Example 2: Same L50, different SR
# Narrow SR = steeper curve; Wide SR = more gradual transition
codends_SR <- data.frame(
gear = c("Narrow SR", "Medium SR", "Wide SR"),
L50 = c(40, 40, 40), # same L50
SR = c(6, 10, 16) # different SR
)
logistic_SR_df <- codends_SR |>
crossing(length = L_grid) |>
mutate(selectivity = logistic_sel(length, L50, SR))
ggplot(logistic_SR_df, aes(x = length, y = selectivity, colour = gear)) +
geom_line(linewidth = 1.1) +
labs(
x = "Length (cm)",
y = "Retention probability",
colour = "Codend",
title = "Logistic selectivity – same L50, different SR"
) +
theme_minimal(base_size = 13)
# Think of mesh size (or hook size) as controlling the "target" fish size.
# Simplified assumption: mean length caught ≈ k * mesh size.
mesh <- c(5, 7.5, 10, 12.5, 15) # e.g., mesh or hook sizes
k_mu <- 8 # scaling factor from mesh to length
sigmaN <- 10 # common spread
normal_df <- data.frame(mesh = mesh) |>
crossing(length = L_grid) |>
mutate(
mu = k_mu * mesh,
selectivity = normal_sel(length, mu, sigmaN)
)
ggplot(normal_df, aes(x = length, y = selectivity, colour = factor(mesh))) +
geom_line(linewidth = 1.1) +
labs(
x = "Length (cm)",
y = "Relative selectivity (scaled to 1)",
colour = "Mesh size",
title = "Normal dome-shaped selectivity – multi-mesh gears"
) +
theme_minimal(base_size = 13)
# Here we allow a more flexible shape:
# e.g., main peak at k*mesh, with a second broader component at larger sizes.
double_df <- data.frame(mesh = mesh) |>
crossing(length = L_grid) |>
mutate(
mu1 = k_mu * mesh, # main mode
mu2 = k_mu * mesh + 20, # second mode
selectivity = double_normal_sel(
length,
mu1 = mu1,
sigma1 = 10,
mu2 = mu2,
sigma2 = 20,
w = 0.7
)
)
ggplot(double_df, aes(x = length, y = selectivity, colour = factor(mesh))) +
geom_line(linewidth = 1.1) +
labs(
x = "Length (cm)",
y = "Relative selectivity (scaled to 1)",
colour = "Mesh size",
title = "Double-normal dome-shaped selectivity – flexible curves"
) +
theme_minimal(base_size = 13)