This report runs quality-control checks on the commercial
fishery (catch) data in the per-member files
(Chile.csv, China.csv, …
Russia.csv). # 1. Load and prepare data
Each member fishes a specific fleet (or two for Chile). The standard ALK template includes empty sheets for all fleets, so we filter to keep only the (member, fleet) combinations that actually correspond to each member’s fishery:
member_fleet <- tribble(
~member, ~fleet_canon,
"Chile", "F1", # Fleet 1: Northern Chile (inside EEZ)
"Chile", "F2", # Fleet 2: South-Central Chile (EEZ/HS)
"Peru", "F3", # Fleet 3: Peru & Ecuador (inside EEZ)
"Ecuador", "F3", # Fleet 3 (Ecuador, same fleet as Peru)
"EU", "F4", # Fleet 4: Offshore (outside EEZ)
"Korea", "F4", # Fleet 4
"China", "F4", # Fleet 4
"Russia", "F4" # Fleet 4
)
member_fleet %>% kable(caption = "Allowed (member, fleet) combinations")
| member | fleet_canon |
|---|---|
| Chile | F1 |
| Chile | F2 |
| Peru | F3 |
| Ecuador | F3 |
| EU | F4 |
| Korea | F4 |
| China | F4 |
| Russia | F4 |
data_dir <- params$data_dir
read_member <- function(m) {
fp <- file.path(data_dir, paste0(m, ".csv"))
if (!file.exists(fp)) {
warning("Missing: ", fp); return(NULL)
}
read_csv(fp, show_col_types = FALSE,
col_types = cols(
submission_year = col_integer(),
data_year = col_integer(),
member = col_character(),
fleet = col_character(),
variable = col_character(),
quarter = col_character(),
length_cm = col_double(),
age = col_integer(),
metric_detail = col_character(),
value = col_double(),
unit = col_character(),
version = col_character(),
data_source = col_character(),
source_file = col_character()
))
}
raw <- bind_rows(lapply(params$members, read_member))
cat("Total rows loaded:", format(nrow(raw), big.mark=","), "\n")
## Total rows loaded: 136,751
Some submissions use full descriptive names (“Fleet 1: Northern Chile (inside EEZ)”), others just “Fleet 1” or “Fleet1”. Collapse to a canonical short label F1/F2/F3/F4:
canon_fleet <- function(x) {
x[is.na(x)] <- ""
x_low <- tolower(x)
x_clean <- str_replace_all(x_low, "[^a-z0-9 ]", " ")
case_when(
str_detect(x_clean, "fleet ?1|northern chile") ~ "F1",
str_detect(x_clean, "fleet ?2|south.?central|eez/hs") ~ "F2",
str_detect(x_clean, "fleet ?3|peru") ~ "F3",
str_detect(x_clean, "fleet ?4|offshore") ~ "F4",
x == "" ~ NA_character_,
TRUE ~ x
)
}
raw <- raw %>% mutate(fleet_canon = canon_fleet(fleet))
For the legacy data sources couldn’t infer a fleet, fall back to the member’s expected fleet (only valid because each member except Chile has exactly one fleet — Chile’s NA-fleet rows would be ambiguous and are dropped):
raw <- raw %>%
left_join(
member_fleet %>% group_by(member) %>%
summarise(default_fleet = ifelse(n() == 1, fleet_canon, NA_character_),
.groups = "drop"),
by = "member"
) %>%
mutate(fleet_canon = coalesce(fleet_canon, default_fleet)) %>%
select(-default_fleet)
n_raw <- nrow(raw)
# 1) version filter
df <- raw %>% filter(!str_detect(version, params$exclude_versions))
cat(sprintf("After version filter: %s rows (%.1f%% of raw)\n",
format(nrow(df), big.mark=","), 100 * nrow(df) / n_raw))
## After version filter: 128,188 rows (93.7% of raw)
# 2) member-fleet allowlist - drop rows from fleets that the member doesn't fish
n_before_allowlist <- nrow(df)
df <- df %>% inner_join(member_fleet, by = c("member","fleet_canon"))
cat(sprintf("After member-fleet allowlist: %s rows (dropped %s)\n",
format(nrow(df), big.mark=","),
format(n_before_allowlist - nrow(df), big.mark=",")))
## After member-fleet allowlist: 107,875 rows (dropped 20,313)
# 3) drop zero-valued rows (zero placeholders are noise, not data)
n_before_zero <- nrow(df)
df <- df %>% filter(!is.na(value), value != 0)
cat(sprintf("After dropping zero/NA values: %s rows (dropped %s)\n",
format(nrow(df), big.mark=","),
format(n_before_zero - nrow(df), big.mark=",")))
## After dropping zero/NA values: 77,935 rows (dropped 29,940)
# 4) dedupe by latest submission per identical
# (member, fleet, year, quarter, length, age, variable, metric_detail, data_source)
if (isTRUE(params$pick_latest_submission)) {
n_before_dedup <- nrow(df)
df <- df %>%
group_by(data_year, member, fleet_canon, variable, quarter,
length_cm, age, metric_detail, data_source) %>%
slice_max(submission_year, n = 1, with_ties = TRUE) %>%
ungroup()
cat(sprintf("After picking latest submission: %s rows (dropped %s)\n",
format(nrow(df), big.mark=","),
format(n_before_dedup - nrow(df), big.mark=",")))
}
## After picking latest submission: 69,557 rows (dropped 8,378)
# Member × fleet labels for plotting
df <- df %>%
mutate(mf = paste(member, fleet_canon, sep = " "),
qtr = factor(quarter, levels = c("Q1","Q2","Q3","Q4","all")))
# Stable factor ordering for mf so plots come out in the same member order
mf_levels <- df %>% distinct(member, fleet_canon, mf) %>%
arrange(member, fleet_canon) %>% pull(mf)
df <- df %>% mutate(mf = factor(mf, levels = mf_levels))
df %>%
count(member, fleet_canon, variable) %>%
pivot_wider(names_from = variable, values_from = n, values_fill = 0) %>%
arrange(member, fleet_canon) %>%
kable(caption = "Row count per (member × fleet) × variable (after all filters)") %>%
kable_styling(bootstrap_options = c("striped","hover"), font_size = 11)
| member | fleet_canon | age_length_key | catch | catch_at_age | catch_at_age_proportion | length_freq | mean_length_at_age | mean_weight_at_age | numbers_at_age | numbers_at_age_proportion | sampling | weight_at_length | age_freq_at_length | age_proportion_at_length |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chile | F1 | 2373 | 64 | 1096 | 1096 | 1453 | 1559 | 1559 | 1559 | 1096 | 189 | 3500 | 0 | 0 |
| Chile | F2 | 4921 | 67 | 1955 | 1955 | 2089 | 2576 | 2576 | 2576 | 1955 | 224 | 3800 | 0 | 0 |
| China | F4 | 54 | 55 | 0 | 0 | 787 | 18 | 18 | 18 | 0 | 54 | 77 | 0 | 0 |
| EU | F4 | 1722 | 49 | 0 | 0 | 1752 | 231 | 230 | 221 | 0 | 112 | 377 | 5884 | 5883 |
| Ecuador | F3 | 0 | 13 | 0 | 0 | 14 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Korea | F4 | 0 | 33 | 0 | 0 | 617 | 0 | 0 | 0 | 0 | 52 | 237 | 0 | 0 |
| Peru | F3 | 4560 | 59 | 0 | 0 | 1688 | 324 | 324 | 325 | 0 | 129 | 238 | 0 | 0 |
| Russia | F4 | 1421 | 36 | 0 | 0 | 691 | 253 | 255 | 255 | 0 | 104 | 149 | 0 | 0 |
Catch is reported by quarter (Q1–Q4). The “all”-quarter aggregate row is excluded to avoid double-counting.
catch <- df %>%
filter(variable == "catch",
metric_detail == "official_landings",
quarter %in% c("Q1","Q2","Q3","Q4")) %>%
group_by(member, fleet_canon, mf, data_year, quarter, qtr) %>%
summarise(catch_t = sum(value, na.rm = TRUE), .groups = "drop")
catch_annual <- catch %>%
group_by(member, fleet_canon, mf, data_year) %>%
summarise(catch_t = sum(catch_t, na.rm = TRUE), .groups = "drop")
ggplot(catch_annual, aes(data_year, catch_t / 1000, fill = mf)) +
geom_col() +
facet_wrap(~ mf, scales = "free_y", ncol = 2) +
scale_x_continuous(breaks = pretty_breaks(6)) +
scale_y_continuous(labels = comma) +
guides(fill = "none") +
labs(title = "Annual catch (official landings)",
x = NULL, y = "Landings (thousand tonnes)")
ggplot(catch, aes(data_year, qtr, fill = catch_t / 1000)) +
geom_tile() +
facet_wrap(~ mf, ncol = 2) +
scale_fill_viridis_c(option = "C", labels = comma, name = "kt") +
scale_x_continuous(breaks = pretty_breaks(6)) +
labs(title = "Catch (thousand tonnes) by year × quarter",
subtitle = "Empty cells = no catch reported that quarter",
x = NULL, y = "Quarter")
catch %>%
pivot_wider(names_from = quarter, values_from = catch_t, values_fill = 0) %>%
mutate(annual = Q1 + Q2 + Q3 + Q4) %>%
arrange(member, fleet_canon, data_year) %>%
mutate(across(c(Q1,Q2,Q3,Q4,annual), ~ round(.x))) %>%
kable(caption = "Catch (tonnes) by quarter, with annual sum") %>%
kable_styling(bootstrap_options = c("striped","hover"), font_size = 11) %>%
scroll_box(height = "400px")
| member | fleet_canon | mf | data_year | qtr | Q1 | Q2 | Q3 | Q4 | annual |
|---|---|---|---|---|---|---|---|---|---|
| Chile | F1 | Chile F1 | 2015 | Q1 | 29539 | 0 | 0 | 0 | 29539 |
| Chile | F1 | Chile F1 | 2015 | Q2 | 0 | 5311 | 0 | 0 | 5311 |
| Chile | F1 | Chile F1 | 2015 | Q3 | 0 | 0 | 7 | 0 | 7 |
| Chile | F1 | Chile F1 | 2015 | Q4 | 0 | 0 | 0 | 29 | 29 |
| Chile | F1 | Chile F1 | 2016 | Q1 | 6 | 0 | 0 | 0 | 6 |
| Chile | F1 | Chile F1 | 2016 | Q2 | 0 | 7102 | 0 | 0 | 7102 |
| Chile | F1 | Chile F1 | 2016 | Q3 | 0 | 0 | 12361 | 0 | 12361 |
| Chile | F1 | Chile F1 | 2017 | Q1 | 17992 | 0 | 0 | 0 | 17992 |
| Chile | F1 | Chile F1 | 2017 | Q2 | 0 | 10153 | 0 | 0 | 10153 |
| Chile | F1 | Chile F1 | 2017 | Q3 | 0 | 0 | 18 | 0 | 18 |
| Chile | F1 | Chile F1 | 2017 | Q4 | 0 | 0 | 0 | 175 | 175 |
| Chile | F1 | Chile F1 | 2019 | Q1 | 134 | 0 | 0 | 0 | 134 |
| Chile | F1 | Chile F1 | 2019 | Q2 | 0 | 1537 | 0 | 0 | 1537 |
| Chile | F1 | Chile F1 | 2019 | Q3 | 0 | 0 | 169 | 0 | 169 |
| Chile | F1 | Chile F1 | 2019 | Q4 | 0 | 0 | 0 | 12719 | 12719 |
| Chile | F1 | Chile F1 | 2020 | Q1 | 7649 | 0 | 0 | 0 | 7649 |
| Chile | F1 | Chile F1 | 2020 | Q2 | 0 | 27784 | 0 | 0 | 27784 |
| Chile | F1 | Chile F1 | 2020 | Q4 | 0 | 0 | 0 | 2567 | 2567 |
| Chile | F1 | Chile F1 | 2021 | Q1 | 35458 | 0 | 0 | 0 | 35458 |
| Chile | F1 | Chile F1 | 2021 | Q2 | 0 | 19334 | 0 | 0 | 19334 |
| Chile | F1 | Chile F1 | 2021 | Q3 | 0 | 0 | 212 | 0 | 212 |
| Chile | F1 | Chile F1 | 2021 | Q4 | 0 | 0 | 0 | 7140 | 7140 |
| Chile | F1 | Chile F1 | 2022 | Q1 | 10925 | 0 | 0 | 0 | 10925 |
| Chile | F1 | Chile F1 | 2022 | Q2 | 0 | 18102 | 0 | 0 | 18102 |
| Chile | F1 | Chile F1 | 2022 | Q3 | 0 | 0 | 12252 | 0 | 12252 |
| Chile | F1 | Chile F1 | 2022 | Q4 | 0 | 0 | 0 | 15202 | 15202 |
| Chile | F1 | Chile F1 | 2023 | Q1 | 60778 | 0 | 0 | 0 | 60778 |
| Chile | F1 | Chile F1 | 2023 | Q2 | 0 | 57325 | 0 | 0 | 57325 |
| Chile | F1 | Chile F1 | 2023 | Q3 | 0 | 0 | 3927 | 0 | 3927 |
| Chile | F1 | Chile F1 | 2023 | Q4 | 0 | 0 | 0 | 14074 | 14074 |
| Chile | F1 | Chile F1 | 2024 | Q1 | 86264 | 0 | 0 | 0 | 86264 |
| Chile | F1 | Chile F1 | 2024 | Q2 | 0 | 71058 | 0 | 0 | 71058 |
| Chile | F1 | Chile F1 | 2024 | Q3 | 0 | 0 | 14566 | 0 | 14566 |
| Chile | F1 | Chile F1 | 2024 | Q4 | 0 | 0 | 0 | 15722 | 15722 |
| Chile | F1 | Chile F1 | 2025 | Q1 | 32802 | 0 | 0 | 0 | 32802 |
| Chile | F2 | Chile F2 | 2015 | Q1 | 38872 | 0 | 0 | 0 | 38872 |
| Chile | F2 | Chile F2 | 2015 | Q2 | 0 | 145825 | 0 | 0 | 145825 |
| Chile | F2 | Chile F2 | 2015 | Q3 | 0 | 0 | 55453 | 0 | 55453 |
| Chile | F2 | Chile F2 | 2015 | Q4 | 0 | 0 | 0 | 10177 | 10177 |
| Chile | F2 | Chile F2 | 2016 | Q1 | 108489 | 0 | 0 | 0 | 108489 |
| Chile | F2 | Chile F2 | 2016 | Q2 | 0 | 133419 | 0 | 0 | 133419 |
| Chile | F2 | Chile F2 | 2016 | Q3 | 0 | 0 | 14182 | 0 | 14182 |
| Chile | F2 | Chile F2 | 2017 | Q1 | 57198 | 0 | 0 | 0 | 57198 |
| Chile | F2 | Chile F2 | 2017 | Q2 | 0 | 158755 | 0 | 0 | 158755 |
| Chile | F2 | Chile F2 | 2017 | Q3 | 0 | 0 | 66026 | 0 | 66026 |
| Chile | F2 | Chile F2 | 2017 | Q4 | 0 | 0 | 0 | 12084 | 12084 |
| Chile | F2 | Chile F2 | 2018 | Q1 | 146376 | 0 | 0 | 0 | 146376 |
| Chile | F2 | Chile F2 | 2019 | Q1 | 205560 | 0 | 0 | 0 | 205560 |
| Chile | F2 | Chile F2 | 2019 | Q2 | 0 | 165061 | 0 | 0 | 165061 |
| Chile | F2 | Chile F2 | 2019 | Q3 | 0 | 0 | 37077 | 0 | 37077 |
| Chile | F2 | Chile F2 | 2019 | Q4 | 0 | 0 | 0 | 20891 | 20891 |
| Chile | F2 | Chile F2 | 2020 | Q1 | 228190 | 0 | 0 | 0 | 228190 |
| Chile | F2 | Chile F2 | 2020 | Q2 | 0 | 128557 | 0 | 0 | 128557 |
| Chile | F2 | Chile F2 | 2020 | Q3 | 0 | 0 | 17550 | 0 | 17550 |
| Chile | F2 | Chile F2 | 2020 | Q4 | 0 | 0 | 0 | 11016 | 11016 |
| Chile | F2 | Chile F2 | 2021 | Q1 | 276076 | 0 | 0 | 0 | 276076 |
| Chile | F2 | Chile F2 | 2021 | Q2 | 0 | 217959 | 0 | 0 | 217959 |
| Chile | F2 | Chile F2 | 2021 | Q3 | 0 | 0 | 48888 | 0 | 48888 |
| Chile | F2 | Chile F2 | 2021 | Q4 | 0 | 0 | 0 | 53659 | 53659 |
| Chile | F2 | Chile F2 | 2022 | Q1 | 214628 | 0 | 0 | 0 | 214628 |
| Chile | F2 | Chile F2 | 2022 | Q2 | 0 | 221402 | 0 | 0 | 221402 |
| Chile | F2 | Chile F2 | 2022 | Q3 | 0 | 0 | 74873 | 0 | 74873 |
| Chile | F2 | Chile F2 | 2022 | Q4 | 0 | 0 | 0 | 67950 | 67950 |
| Chile | F2 | Chile F2 | 2023 | Q1 | 657516 | 0 | 0 | 0 | 657516 |
| Chile | F2 | Chile F2 | 2023 | Q2 | 0 | 545881 | 0 | 0 | 545881 |
| Chile | F2 | Chile F2 | 2023 | Q3 | 0 | 0 | 48614 | 0 | 48614 |
| Chile | F2 | Chile F2 | 2023 | Q4 | 0 | 0 | 0 | 228396 | 228396 |
| Chile | F2 | Chile F2 | 2024 | Q1 | 718491 | 0 | 0 | 0 | 718491 |
| Chile | F2 | Chile F2 | 2024 | Q2 | 0 | 491306 | 0 | 0 | 491306 |
| Chile | F2 | Chile F2 | 2024 | Q3 | 0 | 0 | 210989 | 0 | 210989 |
| Chile | F2 | Chile F2 | 2024 | Q4 | 0 | 0 | 0 | 319834 | 319834 |
| Chile | F2 | Chile F2 | 2025 | Q1 | 371493 | 0 | 0 | 0 | 371493 |
| China | F4 | China F4 | 2016 | Q1 | 4302 | 0 | 0 | 0 | 4302 |
| China | F4 | China F4 | 2016 | Q2 | 0 | 24402 | 0 | 0 | 24402 |
| China | F4 | China F4 | 2016 | Q3 | 0 | 0 | 9147 | 0 | 9147 |
| China | F4 | China F4 | 2016 | Q4 | 0 | 0 | 0 | 2564 | 2564 |
| China | F4 | China F4 | 2017 | Q2 | 0 | 9984 | 0 | 0 | 9984 |
| China | F4 | China F4 | 2017 | Q3 | 0 | 0 | 6601 | 0 | 6601 |
| China | F4 | China F4 | 2018 | Q1 | 1726 | 0 | 0 | 0 | 1726 |
| China | F4 | China F4 | 2018 | Q2 | 0 | 15571 | 0 | 0 | 15571 |
| China | F4 | China F4 | 2018 | Q3 | 0 | 0 | 7091 | 0 | 7091 |
| China | F4 | China F4 | 2019 | Q1 | 3017 | 0 | 0 | 0 | 3017 |
| China | F4 | China F4 | 2019 | Q2 | 0 | 9935 | 0 | 0 | 9935 |
| China | F4 | China F4 | 2019 | Q3 | 0 | 0 | 9762 | 0 | 9762 |
| EU | F4 | EU F4 | 2016 | Q1 | 6484 | 0 | 0 | 0 | 6484 |
| EU | F4 | EU F4 | 2022 | Q2 | 0 | 21341 | 0 | 0 | 21341 |
| EU | F4 | EU F4 | 2022 | Q3 | 0 | 0 | 18862 | 0 | 18862 |
| EU | F4 | EU F4 | 2022 | Q4 | 0 | 0 | 0 | 4061 | 4061 |
| EU | F4 | EU F4 | 2023 | Q2 | 0 | 570 | 0 | 0 | 570 |
| EU | F4 | EU F4 | 2023 | Q3 | 0 | 0 | 10500 | 0 | 10500 |
| EU | F4 | EU F4 | 2025 | Q2 | 0 | 205 | 0 | 0 | 205 |
| EU | F4 | EU F4 | 2025 | Q3 | 0 | 0 | 6450 | 0 | 6450 |
| Ecuador | F3 | Ecuador F3 | 2016 | Q4 | 0 | 0 | 0 | 289 | 289 |
| Ecuador | F3 | Ecuador F3 | 2021 | Q1 | 3 | 0 | 0 | 0 | 3 |
| Ecuador | F3 | Ecuador F3 | 2021 | Q2 | 0 | 1 | 0 | 0 | 1 |
| Ecuador | F3 | Ecuador F3 | 2021 | Q3 | 0 | 0 | 0 | 0 | 0 |
| Ecuador | F3 | Ecuador F3 | 2021 | Q4 | 0 | 0 | 0 | 4 | 4 |
| Korea | F4 | Korea F4 | 2015 | Q2 | 0 | 758 | 0 | 0 | 758 |
| Korea | F4 | Korea F4 | 2015 | Q3 | 0 | 0 | 4990 | 0 | 4990 |
| Korea | F4 | Korea F4 | 2016 | Q2 | 0 | 662 | 0 | 0 | 662 |
| Korea | F4 | Korea F4 | 2016 | Q3 | 0 | 0 | 3176 | 0 | 3176 |
| Korea | F4 | Korea F4 | 2016 | Q4 | 0 | 0 | 0 | 2593 | 2593 |
| Korea | F4 | Korea F4 | 2017 | Q2 | 0 | 91 | 0 | 0 | 91 |
| Korea | F4 | Korea F4 | 2017 | Q3 | 0 | 0 | 1144 | 0 | 1144 |
| Korea | F4 | Korea F4 | 2024 | Q2 | 0 | 0 | 0 | 0 | 0 |
| Korea | F4 | Korea F4 | 2024 | Q3 | 0 | 0 | 1557 | 0 | 1557 |
| Korea | F4 | Korea F4 | 2024 | Q4 | 0 | 0 | 0 | 240 | 240 |
| Peru | F3 | Peru F3 | 2015 | Q1 | 6602 | 0 | 0 | 0 | 6602 |
| Peru | F3 | Peru F3 | 2015 | Q2 | 0 | 6189 | 0 | 0 | 6189 |
| Peru | F3 | Peru F3 | 2015 | Q3 | 0 | 0 | 6256 | 0 | 6256 |
| Peru | F3 | Peru F3 | 2015 | Q4 | 0 | 0 | 0 | 3111 | 3111 |
| Peru | F3 | Peru F3 | 2016 | Q1 | 5094 | 0 | 0 | 0 | 5094 |
| Peru | F3 | Peru F3 | 2016 | Q2 | 0 | 4116 | 0 | 0 | 4116 |
| Peru | F3 | Peru F3 | 2016 | Q3 | 0 | 0 | 3751 | 0 | 3751 |
| Peru | F3 | Peru F3 | 2016 | Q4 | 0 | 0 | 0 | 2127 | 2127 |
| Peru | F3 | Peru F3 | 2017 | Q1 | 1480 | 0 | 0 | 0 | 1480 |
| Peru | F3 | Peru F3 | 2017 | Q2 | 0 | 1739 | 0 | 0 | 1739 |
| Peru | F3 | Peru F3 | 2017 | Q3 | 0 | 0 | 2832 | 0 | 2832 |
| Peru | F3 | Peru F3 | 2017 | Q4 | 0 | 0 | 0 | 2763 | 2763 |
| Peru | F3 | Peru F3 | 2018 | Q1 | 2824 | 0 | 0 | 0 | 2824 |
| Peru | F3 | Peru F3 | 2018 | Q2 | 0 | 2993 | 0 | 0 | 2993 |
| Peru | F3 | Peru F3 | 2018 | Q3 | 0 | 0 | 22074 | 0 | 22074 |
| Peru | F3 | Peru F3 | 2018 | Q4 | 0 | 0 | 0 | 26957 | 26957 |
| Peru | F3 | Peru F3 | 2019 | Q1 | 84679 | 0 | 0 | 0 | 84679 |
| Peru | F3 | Peru F3 | 2019 | Q2 | 0 | 6865 | 0 | 0 | 6865 |
| Peru | F3 | Peru F3 | 2019 | Q3 | 0 | 0 | 24101 | 0 | 24101 |
| Peru | F3 | Peru F3 | 2019 | Q4 | 0 | 0 | 0 | 20139 | 20139 |
| Peru | F3 | Peru F3 | 2020 | Q1 | 89237 | 0 | 0 | 0 | 89237 |
| Peru | F3 | Peru F3 | 2020 | Q2 | 0 | 4266 | 0 | 0 | 4266 |
| Peru | F3 | Peru F3 | 2020 | Q3 | 0 | 0 | 28039 | 0 | 28039 |
| Peru | F3 | Peru F3 | 2020 | Q4 | 0 | 0 | 0 | 18458 | 18458 |
| Peru | F3 | Peru F3 | 2021 | Q1 | 77972 | 0 | 0 | 0 | 77972 |
| Peru | F3 | Peru F3 | 2021 | Q2 | 0 | 13886 | 0 | 0 | 13886 |
| Peru | F3 | Peru F3 | 2021 | Q3 | 0 | 0 | 14533 | 0 | 14533 |
| Peru | F3 | Peru F3 | 2021 | Q4 | 0 | 0 | 0 | 17237 | 17237 |
| Peru | F3 | Peru F3 | 2022 | Q1 | 101707 | 0 | 0 | 0 | 101707 |
| Peru | F3 | Peru F3 | 2022 | Q2 | 0 | 23975 | 0 | 0 | 23975 |
| Peru | F3 | Peru F3 | 2022 | Q3 | 0 | 0 | 6 | 0 | 6 |
| Peru | F3 | Peru F3 | 2022 | Q4 | 0 | 0 | 0 | 33915 | 33915 |
| Peru | F3 | Peru F3 | 2023 | Q1 | 120792 | 0 | 0 | 0 | 120792 |
| Peru | F3 | Peru F3 | 2023 | Q2 | 0 | 9997 | 0 | 0 | 9997 |
| Peru | F3 | Peru F3 | 2024 | Q1 | 7047 | 0 | 0 | 0 | 7047 |
| Peru | F3 | Peru F3 | 2024 | Q2 | 0 | 56934 | 0 | 0 | 56934 |
| Peru | F3 | Peru F3 | 2024 | Q3 | 0 | 0 | 149603 | 0 | 149603 |
| Peru | F3 | Peru F3 | 2024 | Q4 | 0 | 0 | 0 | 3628 | 3628 |
| Peru | F3 | Peru F3 | 2025 | Q1 | 99725 | 0 | 0 | 0 | 99725 |
| Peru | F3 | Peru F3 | 2025 | Q2 | 0 | 7061 | 0 | 0 | 7061 |
| Russia | F4 | Russia F4 | 2019 | Q1 | 432 | 0 | 0 | 0 | 432 |
| Russia | F4 | Russia F4 | 2019 | Q2 | 0 | 2745 | 0 | 0 | 2745 |
| Russia | F4 | Russia F4 | 2019 | Q3 | 0 | 0 | 6246 | 0 | 6246 |
| Russia | F4 | Russia F4 | 2020 | Q3 | 0 | 0 | 3378 | 0 | 3378 |
| Russia | F4 | Russia F4 | 2020 | Q4 | 0 | 0 | 0 | 1867 | 1867 |
| Russia | F4 | Russia F4 | 2021 | Q1 | 156 | 0 | 0 | 0 | 156 |
| Russia | F4 | Russia F4 | 2021 | Q2 | 0 | 4523 | 0 | 0 | 4523 |
| Russia | F4 | Russia F4 | 2021 | Q3 | 0 | 0 | 7472 | 0 | 7472 |
| Russia | F4 | Russia F4 | 2022 | Q2 | 0 | 9136 | 0 | 0 | 9136 |
| Russia | F4 | Russia F4 | 2022 | Q3 | 0 | 0 | 9111 | 0 | 9111 |
| Russia | F4 | Russia F4 | 2022 | Q4 | 0 | 0 | 0 | 11660 | 11660 |
| Russia | F4 | Russia F4 | 2023 | Q1 | 2774 | 0 | 0 | 0 | 2774 |
| Russia | F4 | Russia F4 | 2023 | Q2 | 0 | 10099 | 0 | 0 | 10099 |
| Russia | F4 | Russia F4 | 2023 | Q3 | 0 | 0 | 15131 | 0 | 15131 |
| Russia | F4 | Russia F4 | 2023 | Q4 | 0 | 0 | 0 | 13137 | 13137 |
| Russia | F4 | Russia F4 | 2024 | Q2 | 0 | 261 | 0 | 0 | 261 |
| Russia | F4 | Russia F4 | 2024 | Q3 | 0 | 0 | 7968 | 0 | 7968 |
| Russia | F4 | Russia F4 | 2024 | Q4 | 0 | 0 | 0 | 3881 | 3881 |
sampling <- df %>%
filter(variable == "sampling",
metric_detail %in% c("samples","samples_1","samples_2","measured","aged",
"total_of_sample")) %>%
mutate(stream = case_when(
metric_detail == "aged" ~ "aged",
metric_detail == "total_of_sample" ~ "sampled_weight_t",
metric_detail %in% c("measured","samples","samples_1","samples_2") ~ "measured"
)) %>%
group_by(member, fleet_canon, mf, data_year, quarter, qtr, stream) %>%
summarise(value = sum(value, na.rm = TRUE), .groups = "drop")
sampling %>%
filter(quarter == "all", stream %in% c("measured","aged")) %>%
mutate(year_f = factor(data_year)) %>%
ggplot(aes(year_f, value, fill = stream)) +
geom_col(position = position_dodge(width = 0.8), width = 0.75) +
facet_wrap(~ mf, scales = "free_y", ncol = 2) +
scale_y_continuous(labels = comma) +
scale_fill_brewer(palette = "Set1") +
theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)) +
labs(title = "Annual sampling effort: number of fish measured / aged",
x = NULL, y = "Fish (n)", fill = NULL)
sw <- sampling %>%
filter(quarter == "all", stream == "sampled_weight_t")
if (nrow(sw)) {
sw %>%
mutate(year_f = factor(data_year)) %>%
ggplot(aes(year_f, value, fill = mf)) +
geom_col(width = 0.75) +
facet_wrap(~ mf, scales = "free_y", ncol = 2) +
scale_y_continuous(labels = comma) +
guides(fill = "none") +
theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1)) +
labs(title = "Annual sampled weight (tonnes)",
x = NULL, y = "Sampled weight (tonnes)")
} else {
cat("No annual sampled weight data after filtering.\n")
}
sampling %>%
filter(stream == "measured", quarter %in% c("Q1","Q2","Q3","Q4")) %>%
ggplot(aes(data_year, qtr, fill = value)) +
geom_tile() +
facet_wrap(~ mf, ncol = 2) +
scale_fill_viridis_c(option = "C", labels = comma, name = "fish") +
labs(title = "Number of fish measured by year × quarter",
x = NULL, y = "Quarter")
sampling %>%
filter(stream == "aged", quarter %in% c("Q1","Q2","Q3","Q4")) %>%
ggplot(aes(data_year, qtr, fill = value)) +
geom_tile() +
facet_wrap(~ mf, ncol = 2) +
scale_fill_viridis_c(option = "C", labels = comma, name = "fish") +
labs(title = "Number of fish aged by year × quarter",
x = NULL, y = "Quarter")
sw_q <- sampling %>%
filter(stream == "sampled_weight_t", quarter %in% c("Q1","Q2","Q3","Q4"))
if (nrow(sw_q)) {
ggplot(sw_q, aes(data_year, qtr, fill = value)) +
geom_tile() +
facet_wrap(~ mf, ncol = 2) +
scale_fill_viridis_c(option = "C", labels = comma, name = "tonnes") +
labs(title = "Sampled weight (tonnes) by year × quarter",
x = NULL, y = "Quarter")
} else {
cat("No quarterly sampled-weight data after filtering.\n")
}
sampling %>%
filter(quarter == "all") %>%
pivot_wider(names_from = stream, values_from = value) %>%
arrange(member, fleet_canon, data_year) %>%
mutate(across(where(is.numeric) & !data_year, ~ round(.x, 1))) %>%
kable(caption = "Annual sampling: fish measured / aged and sampled weight (tonnes)") %>%
kable_styling(bootstrap_options = c("striped","hover"), font_size = 11) %>%
scroll_box(height = "400px")
| member | fleet_canon | mf | data_year | quarter | qtr | aged | measured | sampled_weight_t |
|---|---|---|---|---|---|---|---|---|
| Chile | F1 | Chile F1 | 2015 | all | all | 54 | 118 | 25982.3 |
| Chile | F1 | Chile F1 | 2016 | all | all | NA | 38 | NA |
| Chile | F1 | Chile F1 | 2017 | all | all | 230 | 7882 | NA |
| Chile | F1 | Chile F1 | 2019 | all | all | 123 | 409 | 13258.8 |
| Chile | F1 | Chile F1 | 2020 | all | all | 175 | 646 | 38338.2 |
| Chile | F1 | Chile F1 | 2021 | all | all | 342 | 1175 | 62144.7 |
| Chile | F1 | Chile F1 | 2022 | all | all | 551 | 2375 | 56481.0 |
| Chile | F1 | Chile F1 | 2023 | all | all | 1376 | 6944 | 136104.6 |
| Chile | F1 | Chile F1 | 2024 | all | all | 1954 | 11664 | 187609.5 |
| Chile | F1 | Chile F1 | 2025 | all | all | 207 | 1289 | 32802.4 |
| Chile | F2 | Chile F2 | 2015 | all | all | 1995 | 7849 | 132943.5 |
| Chile | F2 | Chile F2 | 2016 | all | all | 414 | 4231 | NA |
| Chile | F2 | Chile F2 | 2017 | all | all | 1872 | 50776 | NA |
| Chile | F2 | Chile F2 | 2018 | all | all | 616 | 17136 | NA |
| Chile | F2 | Chile F2 | 2019 | all | all | 1926 | 19836 | 438567.6 |
| Chile | F2 | Chile F2 | 2020 | all | all | 1578 | 25215 | 388214.8 |
| Chile | F2 | Chile F2 | 2021 | all | all | 1833 | 28997 | 596290.8 |
| Chile | F2 | Chile F2 | 2022 | all | all | 1725 | 21638 | 578853.0 |
| Chile | F2 | Chile F2 | 2023 | all | all | 4064 | 71164 | 1480406.9 |
| Chile | F2 | Chile F2 | 2024 | all | all | 3910 | 65336 | 1740620.0 |
| Chile | F2 | Chile F2 | 2025 | all | all | 427 | 10604 | 371493.1 |
| China | F4 | China F4 | 2016 | all | all | 600 | 2660 | 1330.0 |
| China | F4 | China F4 | 2018 | all | all | NA | 24378 | 6.1 |
| China | F4 | China F4 | 2019 | all | all | NA | 23802 | 12.6 |
| EU | F4 | EU F4 | 2016 | all | all | NA | 7699 | 3819.0 |
| EU | F4 | EU F4 | 2017 | all | all | 1625 | 13943 | 4817.0 |
| EU | F4 | EU F4 | 2018 | all | all | 1000 | 7542 | 4120.0 |
| EU | F4 | EU F4 | 2019 | all | all | 251 | 5204 | 5185.0 |
| EU | F4 | EU F4 | 2021 | all | all | 212 | 11929 | 5808.8 |
| EU | F4 | EU F4 | 2022 | all | all | 535 | 21416 | 19619.8 |
| EU | F4 | EU F4 | 2023 | all | all | 794 | 28110 | 7.7 |
| EU | F4 | EU F4 | 2024 | all | all | 67 | 8844 | 17772.9 |
| EU | F4 | EU F4 | 2025 | all | all | NA | 11220 | NA |
| Korea | F4 | Korea F4 | 2014 | all | all | NA | NA | 0.1 |
| Korea | F4 | Korea F4 | 2015 | all | all | NA | 4482 | 1.0 |
| Korea | F4 | Korea F4 | 2016 | all | all | NA | 16340 | 2.2 |
| Korea | F4 | Korea F4 | 2017 | all | all | NA | 3134 | 0.5 |
| Korea | F4 | Korea F4 | 2019 | all | all | NA | 14314 | 1.1 |
| Korea | F4 | Korea F4 | 2024 | all | all | NA | 13198 | NA |
| Peru | F3 | Peru F3 | 2015 | all | all | NA | 3169 | 110.0 |
| Peru | F3 | Peru F3 | 2017 | all | all | NA | 19064 | 233.1 |
| Peru | F3 | Peru F3 | 2018 | all | all | NA | 43581 | 20428.6 |
| Peru | F3 | Peru F3 | 2019 | all | all | NA | 60454 | 8408.8 |
| Peru | F3 | Peru F3 | 2020 | all | all | NA | 67113 | 55984.3 |
| Peru | F3 | Peru F3 | 2021 | all | all | NA | 48704 | 13229.7 |
| Peru | F3 | Peru F3 | 2022 | all | all | NA | 54409 | 24270.6 |
| Peru | F3 | Peru F3 | 2023 | all | all | NA | 40134 | 34655.7 |
| Peru | F3 | Peru F3 | 2024 | all | all | NA | 46198 | 23282.9 |
| Peru | F3 | Peru F3 | 2025 | all | all | NA | 23010 | 11750.9 |
| Russia | F4 | Russia F4 | 2019 | all | all | 1548 | 24833 | 4114.0 |
| Russia | F4 | Russia F4 | 2020 | all | all | 529 | 18373 | 3935.0 |
| Russia | F4 | Russia F4 | 2021 | all | all | 778 | 22614 | 7.9 |
| Russia | F4 | Russia F4 | 2022 | all | all | 2226 | 36627 | 12466.3 |
| Russia | F4 | Russia F4 | 2023 | all | all | 2023 | 61922 | 15040.0 |
| Russia | F4 | Russia F4 | 2024 | all | all | 698 | 13184 | 1959.0 |
We use only the standard template’s length-frequency rows
(data_source == "STANDARD_TEMPLATE").
lfd_q <- df %>%
filter(variable == "length_freq",
data_source == "STANDARD_TEMPLATE",
quarter %in% c("Q1","Q2","Q3","Q4"),
!is.na(length_cm)) %>%
group_by(member, fleet_canon, mf, data_year, quarter, qtr, length_cm) %>%
summarise(n_thousands = sum(value, na.rm = TRUE), .groups = "drop")
lfd_yr <- df %>%
filter(variable == "length_freq",
data_source == "STANDARD_TEMPLATE",
quarter == "all",
!is.na(length_cm)) %>%
group_by(member, fleet_canon, mf, data_year, length_cm) %>%
summarise(n_thousands = sum(value, na.rm = TRUE), .groups = "drop")
# Numbers-weighted-quantile helper
wq <- function(x, w, p) {
ord <- order(x)
x <- x[ord]; w <- w[ord]
if (!length(x) || !is.finite(sum(w)) || sum(w) <= 0) return(NA_real_)
cw <- cumsum(w) / sum(w)
approx(cw, x, xout = p, ties = "ordered", rule = 2)$y
}
lfd_stats_q <- lfd_q %>%
group_by(member, fleet_canon, mf, data_year, quarter, qtr) %>%
summarise(n_total_thousands = sum(n_thousands),
mean_len = sum(length_cm * n_thousands) / sum(n_thousands),
p25_len = wq(length_cm, n_thousands, 0.25),
median_len = wq(length_cm, n_thousands, 0.50),
p75_len = wq(length_cm, n_thousands, 0.75),
mode_len = length_cm[which.max(n_thousands)],
.groups = "drop")
ggplot(lfd_yr, aes(length_cm, n_thousands, group = data_year, color = data_year)) +
geom_line(alpha = 0.6, linewidth = 0.4) +
facet_wrap(~ mf, scales = "free_y", ncol = 2) +
scale_color_viridis_c() +
scale_y_continuous(labels = comma) +
labs(title = "Annual length-frequency (one line per year)",
x = "Fork length (cm)", y = "Numbers (thousands)", color = "Year")
ggplot(lfd_q, aes(length_cm, n_thousands, group = data_year, color = data_year)) +
geom_line(alpha = 0.6, linewidth = 0.35) +
facet_grid(mf ~ qtr, scales = "free_y") +
scale_color_viridis_c() +
scale_y_continuous(labels = comma) +
labs(title = "Quarterly length-frequency (one line per year)",
x = "Fork length (cm)", y = "Numbers (thousands)", color = "Year")
ggplot(lfd_stats_q, aes(data_year, mean_len, color = qtr)) +
geom_line() + geom_point(size = 1.2) +
facet_wrap(~ mf, ncol = 2) +
scale_color_brewer(palette = "Set1", name = "Quarter") +
scale_x_continuous(breaks = pretty_breaks(6)) +
labs(title = "Numbers-weighted mean length per quarter, by year",
x = NULL, y = "Mean fork length (cm)")
For each (member, fleet) the length-frequency distribution within each (year, quarter) cell, normalized to a proportion (sums to 1 per year × quarter). Y-axis is proportion, X-axis is fork length, panels are year × quarter. Lets you see shifts in the distribution within a year and across years.
# Compute per (mf, year, quarter) proportion-at-length
lfd_prop <- lfd_q %>%
group_by(member, fleet_canon, mf, data_year, quarter, qtr) %>%
mutate(prop = n_thousands / sum(n_thousands, na.rm = TRUE)) %>%
ungroup() %>%
filter(is.finite(prop), prop > 0)
plot_lfd_prop <- function(this_mf) {
d <- lfd_prop %>% filter(mf == this_mf)
if (!nrow(d)) {
cat("No data for", this_mf, "\n"); return(invisible(NULL))
}
ggplot(d, aes(length_cm, prop)) +
geom_col(fill = "steelblue", width = 1) +
facet_grid(data_year ~ qtr, switch = "y") +
scale_y_continuous(labels = percent_format(accuracy = 1),
breaks = pretty_breaks(2)) +
scale_x_continuous(breaks = pretty_breaks(5)) +
theme(strip.text.y.left = element_text(angle = 0),
panel.spacing = unit(0.2, "lines")) +
labs(title = paste0("Length composition (proportion) — ", this_mf),
x = "Fork length (cm)", y = "Proportion")
}
plot_lfd_prop("Chile F1")
plot_lfd_prop("Chile F2")
plot_lfd_prop("China F4")
plot_lfd_prop("Ecuador F3")
plot_lfd_prop("EU F4")
plot_lfd_prop("Korea F4")
plot_lfd_prop("Peru F3")
plot_lfd_prop("Russia F4")
lfd_range <- lfd_yr %>%
filter(n_thousands > 0) %>%
group_by(member, fleet_canon, mf, data_year) %>%
summarise(min_len = min(length_cm), max_len = max(length_cm),
n_lengths = n_distinct(length_cm),
total_thousands = sum(n_thousands),
.groups = "drop")
ggplot(lfd_range, aes(data_year)) +
geom_linerange(aes(ymin = min_len, ymax = max_len), color = "steelblue") +
geom_point(aes(y = min_len), size = 1.5, color = "steelblue") +
geom_point(aes(y = max_len), size = 1.5, color = "steelblue") +
facet_wrap(~ mf, ncol = 2) +
geom_hline(yintercept = c(10, 75), linetype = "dashed", color = "red") +
labs(title = "Length range observed per year",
subtitle = "Red dashed lines = biologically plausible range (10–75 cm)",
x = NULL, y = "Fork length (cm)")
lfd_flags <- lfd_yr %>%
filter(n_thousands > 0, (length_cm < 10 | length_cm > 75)) %>%
arrange(desc(n_thousands))
if (nrow(lfd_flags)) {
lfd_flags %>%
head(50) %>%
kable(caption = paste0("Lengths outside 10–75 cm with non-zero counts (top 50 of ",
nrow(lfd_flags), ")"), digits = 1) %>%
kable_styling(bootstrap_options = c("striped","hover"), font_size = 10) %>%
scroll_box(height = "300px")
} else {
cat("No length values outside 10–75 cm.\n")
}
| member | fleet_canon | mf | data_year | length_cm | n_thousands |
|---|---|---|---|---|---|
| Chile | F1 | Chile F1 | 2019 | 9 | 244511.1 |
| Chile | F1 | Chile F1 | 2019 | 8 | 181100.9 |
| Chile | F2 | Chile F2 | 2019 | 9 | 25645.7 |
| Chile | F2 | Chile F2 | 2019 | 8 | 20516.6 |
| Chile | F1 | Chile F1 | 2023 | 9 | 3171.2 |
| Chile | F1 | Chile F1 | 2023 | 8 | 1934.5 |
| Chile | F1 | Chile F1 | 2015 | 9 | 311.3 |
| Chile | F1 | Chile F1 | 2023 | 7 | 281.2 |
| Chile | F1 | Chile F1 | 2024 | 9 | 214.2 |
| Peru | F3 | Peru F3 | 2021 | 9 | 64.6 |
| Chile | F1 | Chile F1 | 2015 | 8 | 51.9 |
| Chile | F1 | Chile F1 | 2021 | 9 | 29.8 |
| Peru | F3 | Peru F3 | 2021 | 8 | 2.8 |
Successive years’ LFD totals differing by more than 100× usually indicate a unit/scaling change between submissions.
lfd_year_totals <- lfd_yr %>%
group_by(member, fleet_canon, mf, data_year) %>%
summarise(total_thousands = sum(n_thousands), .groups = "drop") %>%
arrange(member, fleet_canon, data_year) %>%
group_by(member, fleet_canon, mf) %>%
mutate(prev = lag(total_thousands),
ratio = ifelse(prev > 0, total_thousands / prev, NA_real_)) %>%
ungroup()
scale_shifts <- lfd_year_totals %>% filter(!is.na(ratio), (ratio > 100 | ratio < 1/100))
if (nrow(scale_shifts)) {
scale_shifts %>%
arrange(desc(abs(log10(ratio)))) %>%
mutate(across(c(total_thousands, prev), ~ formatC(.x, format="e", digits=2)),
ratio = round(ratio, 2)) %>%
kable(caption = "LFD-total ratio outside [1/100, 100]") %>%
kable_styling(bootstrap_options = c("striped","hover"), font_size = 10) %>%
scroll_box(height = "300px")
} else {
cat("No suspicious 100x year-on-year LFD scale changes.\n")
}
| member | fleet_canon | mf | data_year | total_thousands | prev | ratio |
|---|---|---|---|---|---|---|
| Chile | F2 | Chile F2 | 2017 | 6.50e+08 | 2.76e+05 | 2350.41 |
| Chile | F2 | Chile F2 | 2020 | 6.38e+05 | 9.39e+08 | 0.00 |
| Chile | F1 | Chile F1 | 2017 | 1.91e+08 | 1.63e+05 | 1169.87 |
| Chile | F1 | Chile F1 | 2020 | 1.23e+05 | 3.11e+07 | 0.00 |
The standard template’s WLK sheet is reported by quarter only — there is no annual aggregate row. So this section shows quarterly views only.
wlk <- df %>%
filter(variable == "weight_at_length",
data_source == "STANDARD_TEMPLATE",
!is.na(length_cm), value > 0) %>%
group_by(member, fleet_canon, mf, data_year, quarter, qtr, length_cm) %>%
summarise(mean_w_kg = mean(value), .groups = "drop")
wlk %>%
filter(quarter %in% c("Q1","Q2","Q3","Q4")) %>%
ggplot(aes(length_cm, mean_w_kg, group = data_year, color = data_year)) +
geom_line(alpha = 0.6, linewidth = 0.35) +
facet_grid(mf ~ qtr, scales = "free_y") +
scale_color_viridis_c() +
labs(title = "Mean weight-at-length by quarter",
x = "Fork length (cm)", y = "Mean weight (kg)", color = "Year")
canum_q <- df %>%
filter(variable == "numbers_at_age",
metric_detail == "numbers_at_age",
quarter %in% c("Q1","Q2","Q3","Q4"),
!is.na(age)) %>%
group_by(member, fleet_canon, mf, data_year, quarter, qtr, age) %>%
summarise(n_thousands = sum(value), .groups = "drop")
canum_yr <- df %>%
filter(variable == "numbers_at_age",
metric_detail == "numbers_at_age",
quarter == "all",
!is.na(age)) %>%
group_by(member, fleet_canon, mf, data_year, age) %>%
summarise(n_thousands = sum(value), .groups = "drop")
ggplot(canum_yr, aes(age, n_thousands, group = data_year, color = data_year)) +
geom_line(alpha = 0.6) +
facet_wrap(~ mf, scales = "free_y", ncol = 2) +
scale_color_viridis_c() +
scale_x_continuous(breaks = 0:12) +
scale_y_continuous(labels = comma) +
labs(title = "Numbers at age — annual",
x = "Age", y = "Numbers (thousands)", color = "Year")
ggplot(canum_q, aes(age, n_thousands, group = data_year, color = data_year)) +
geom_line(alpha = 0.6, linewidth = 0.35) +
facet_grid(mf ~ qtr, scales = "free_y") +
scale_color_viridis_c() +
scale_x_continuous(breaks = 0:12) +
scale_y_continuous(labels = comma) +
labs(title = "Numbers at age — quarterly",
x = "Age", y = "Numbers (thousands)", color = "Year")
mean_age_q <- canum_q %>%
group_by(member, fleet_canon, mf, data_year, quarter, qtr) %>%
summarise(mean_age = sum(age * n_thousands, na.rm=TRUE) / sum(n_thousands, na.rm=TRUE),
.groups = "drop")
ggplot(mean_age_q, aes(data_year, mean_age, color = qtr)) +
geom_line() + geom_point(size = 1.2) +
facet_wrap(~ mf, ncol = 2) +
scale_color_brewer(palette = "Set1", name = "Quarter") +
scale_x_continuous(breaks = pretty_breaks(6)) +
labs(title = "Mean age in catch over time, by quarter",
x = NULL, y = "Mean age (years)")
For each (member, fleet) the age distribution within each (year, quarter) cell, normalized to a proportion (sums to 1 per year × quarter). Y-axis is proportion, X-axis is age, panels are year × quarter. Lets you visually track cohort progression.
canum_prop <- canum_q %>%
group_by(member, fleet_canon, mf, data_year, quarter, qtr) %>%
mutate(prop = n_thousands / sum(n_thousands, na.rm = TRUE)) %>%
ungroup() %>%
filter(is.finite(prop), prop > 0)
plot_canum_prop <- function(this_mf) {
d <- canum_prop %>% filter(mf == this_mf)
if (!nrow(d)) {
cat("No data for", this_mf, "\n"); return(invisible(NULL))
}
ggplot(d, aes(age, prop)) +
geom_col(fill = "darkgreen", width = 0.85) +
facet_grid(data_year ~ qtr, switch = "y") +
scale_y_continuous(labels = percent_format(accuracy = 1),
breaks = pretty_breaks(2)) +
scale_x_continuous(breaks = 0:12) +
theme(strip.text.y.left = element_text(angle = 0),
panel.spacing = unit(0.2, "lines")) +
labs(title = paste0("Age composition (proportion) — ", this_mf),
x = "Age", y = "Proportion")
}
plot_canum_prop("Chile F1")
plot_canum_prop("Chile F2")
plot_canum_prop("China F4")
plot_canum_prop("EU F4")
plot_canum_prop("Peru F3")
plot_canum_prop("Russia F4")
age_range <- canum_yr %>%
filter(n_thousands > 0) %>%
group_by(member, fleet_canon, mf, data_year) %>%
summarise(min_age = min(age), max_age = max(age),
n_ages = n_distinct(age),
total_thousands = round(sum(n_thousands)),
.groups = "drop") %>%
arrange(member, fleet_canon, data_year)
age_range %>%
kable(caption = "Age range and total numbers per (mf × year)") %>%
kable_styling(bootstrap_options = c("striped","hover"), font_size = 11) %>%
scroll_box(height = "400px")
| member | fleet_canon | mf | data_year | min_age | max_age | n_ages | total_thousands |
|---|---|---|---|---|---|---|---|
| Chile | F1 | Chile F1 | 2015 | 1 | 8 | 8 | 163287 |
| Chile | F1 | Chile F1 | 2017 | 1 | 12 | 12 | 191021732 |
| Chile | F1 | Chile F1 | 2019 | 0 | 12 | 13 | 31113983 |
| Chile | F1 | Chile F1 | 2020 | 2 | 12 | 10 | 122977 |
| Chile | F1 | Chile F1 | 2021 | 0 | 12 | 13 | 121214 |
| Chile | F1 | Chile F1 | 2022 | 0 | 12 | 12 | 92941 |
| Chile | F1 | Chile F1 | 2023 | 0 | 12 | 13 | 214187 |
| Chile | F1 | Chile F1 | 2024 | 0 | 11 | 12 | 266236 |
| Chile | F1 | Chile F1 | 2025 | 1 | 12 | 12 | 47784 |
| Chile | F2 | Chile F2 | 2015 | 1 | 12 | 12 | 413967 |
| Chile | F2 | Chile F2 | 2016 | 1 | 12 | 11 | 276589 |
| Chile | F2 | Chile F2 | 2017 | 1 | 12 | 12 | 649653564 |
| Chile | F2 | Chile F2 | 2018 | 3 | 12 | 10 | 353682021 |
| Chile | F2 | Chile F2 | 2019 | 0 | 12 | 13 | 939068051 |
| Chile | F2 | Chile F2 | 2020 | 2 | 12 | 11 | 637768 |
| Chile | F2 | Chile F2 | 2021 | 1 | 12 | 12 | 1010447 |
| Chile | F2 | Chile F2 | 2022 | 0 | 12 | 13 | 732050 |
| Chile | F2 | Chile F2 | 2023 | 1 | 12 | 12 | 2072759 |
| Chile | F2 | Chile F2 | 2024 | 2 | 12 | 11 | 2955686 |
| Chile | F2 | Chile F2 | 2025 | 2 | 12 | 11 | 710427 |
| China | F4 | China F4 | 2016 | 3 | 9 | 7 | 47914 |
| EU | F4 | EU F4 | 2016 | 2 | 12 | 8 | 25235 |
| EU | F4 | EU F4 | 2017 | 1 | 8 | 8 | 90481 |
| EU | F4 | EU F4 | 2018 | 2 | 10 | 9 | 13336 |
| EU | F4 | EU F4 | 2019 | 2 | 10 | 9 | 11657 |
| EU | F4 | EU F4 | 2021 | 1 | 6 | 6 | 109769 |
| EU | F4 | EU F4 | 2022 | 2 | 12 | 11 | 227023 |
| EU | F4 | EU F4 | 2023 | 2 | 12 | 11 | 207262 |
| EU | F4 | EU F4 | 2024 | 1 | 9 | 9 | 9693 |
| Peru | F3 | Peru F3 | 2017 | 0 | 7 | 8 | 81340 |
| Peru | F3 | Peru F3 | 2018 | 1 | 7 | 7 | 204490 |
| Peru | F3 | Peru F3 | 2019 | 1 | 7 | 7 | 340229 |
| Peru | F3 | Peru F3 | 2020 | 1 | 7 | 7 | 284476 |
| Peru | F3 | Peru F3 | 2021 | 0 | 12 | 9 | 173103 |
| Peru | F3 | Peru F3 | 2022 | 1 | 12 | 8 | 222692 |
| Peru | F3 | Peru F3 | 2023 | 1 | 12 | 8 | 196917 |
| Peru | F3 | Peru F3 | 2024 | 1 | 12 | 8 | 227336 |
| Peru | F3 | Peru F3 | 2025 | 1 | 12 | 8 | 108686 |
| Russia | F4 | Russia F4 | 2019 | 1 | 12 | 12 | 44609 |
| Russia | F4 | Russia F4 | 2020 | 1 | 11 | 11 | 24947 |
| Russia | F4 | Russia F4 | 2021 | 0 | 12 | 12 | 49059 |
| Russia | F4 | Russia F4 | 2022 | 0 | 12 | 13 | 131953 |
| Russia | F4 | Russia F4 | 2023 | 1 | 12 | 12 | 167108 |
| Russia | F4 | Russia F4 | 2024 | 0 | 11 | 12 | 40347 |
mlaa <- df %>%
filter(variable == "mean_length_at_age",
metric_detail == "mean_length_cm",
!is.na(age)) %>%
group_by(member, fleet_canon, mf, data_year, quarter, qtr, age) %>%
summarise(mean_len = mean(value, na.rm = TRUE), .groups = "drop")
mwaa <- df %>%
filter(variable == "mean_weight_at_age",
metric_detail == "mean_weight",
!is.na(age)) %>%
group_by(member, fleet_canon, mf, data_year, quarter, qtr, age) %>%
summarise(mean_w_kg = mean(value, na.rm = TRUE), .groups = "drop")
mlaa %>%
filter(quarter == "all") %>%
ggplot(aes(age, mean_len, group = data_year, color = data_year)) +
geom_line(alpha = 0.6) +
facet_wrap(~ mf, scales = "free_y", ncol = 2) +
scale_color_viridis_c() +
scale_x_continuous(breaks = 0:12) +
labs(title = "Mean length at age (annual)",
x = "Age", y = "Mean length (cm)", color = "Year")
mlaa %>%
filter(quarter %in% c("Q1","Q2","Q3","Q4")) %>%
ggplot(aes(age, mean_len, group = data_year, color = data_year)) +
geom_line(alpha = 0.6, linewidth = 0.35) +
facet_grid(mf ~ qtr, scales = "free_y") +
scale_color_viridis_c() +
scale_x_continuous(breaks = 0:12) +
labs(title = "Mean length at age — by quarter",
x = "Age", y = "Mean length (cm)", color = "Year")
mwaa %>%
filter(quarter == "all") %>%
ggplot(aes(age, mean_w_kg, group = data_year, color = data_year)) +
geom_line(alpha = 0.6) +
facet_wrap(~ mf, scales = "free_y", ncol = 2) +
scale_color_viridis_c() +
scale_x_continuous(breaks = 0:12) +
labs(title = "Mean weight at age (annual)",
x = "Age", y = "Mean weight (kg)", color = "Year")
mwaa %>%
filter(quarter %in% c("Q1","Q2","Q3","Q4")) %>%
ggplot(aes(age, mean_w_kg, group = data_year, color = data_year)) +
geom_line(alpha = 0.6, linewidth = 0.35) +
facet_grid(mf ~ qtr, scales = "free_y") +
scale_color_viridis_c() +
scale_x_continuous(breaks = 0:12) +
labs(title = "Mean weight at age — by quarter",
x = "Age", y = "Mean weight (kg)", color = "Year")