knitr::opts_chunk$set(cache = FALSE)
# libraries
library(ggplot2)
library(magrittr)
library(tidytext)
library(apexcharter)


setwd("../..")
pars <- peskas.timor.data.pipeline::read_config()


kobo_trips <- peskas.timor.data.pipeline::get_merged_trips(pars) %>% dplyr::filter(.data$landing_date >= "2018-01-01")
metadata <- peskas.timor.data.pipeline::get_preprocessed_sheets(pars)
nutrients_table <- peskas.timor.data.pipeline::get_nutrients_table(pars)
estimates <- peskas.timor.data.pipeline::get_models(pars)

vessels_stats <-
  metadata$vessels_stats %>%
  dplyr::group_by(.data$reporting_region) %>%
  dplyr::summarise(n_boats = sum(.data$n_boats)) %>%
  dplyr::ungroup()

# palettes
year_palette <-
  rev(c("#bda639", "#1b5767", "#629a9b", "#c51f5d", "#92684d", "#9ECE9A", "firebrick"))
catch_use_palette <- rev(c("#9f8985", "#87bdbc", "#dbdbc9"))
nut_palette <- c("#E07A5F","#3D405B","#81B29A","#F2CC8F","#0a9396","#b392ac")

# help functions
label_date <- function(x) {
  format(x, "%b") %>%
    stringr::str_replace("Jan", paste0("Jan\n", format(x, "%Y")))
}

RDI_tab <- dplyr::tibble(
  nutrient = c("selenium", "zinc", "protein", "omega3", "calcium", "iron", "vitaminA"),
  conv_factor = c(
    pars$metadata$nutrients$RDI$name$selenium,
    pars$metadata$nutrients$RDI$name$zinc,
    pars$metadata$nutrients$RDI$name$protein,
    pars$metadata$nutrients$RDI$name$omega3,
    pars$metadata$nutrients$RDI$name$calcium,
    pars$metadata$nutrients$RDI$name$iron,
    pars$metadata$nutrients$RDI$name$vitaminA
  )
)
rename_nutrients_mu <- function(df = NULL, hyphen = FALSE) {
  if (isFALSE(hyphen)) {
    df %>%
      dplyr::rename_with(~ tolower(.), dplyr::everything()) %>%
      dplyr::rename_with(~ gsub("_mu$", "", .), dplyr::everything()) %>%
      dplyr::rename_with(~ gsub("omega_3", "omega3", .), dplyr::everything()) %>%
      dplyr::rename_with(~ gsub("vitamin_a", "vitaminA", .), dplyr::everything())
  } else {
    df %>%
      dplyr::rename_with(~ tolower(.), dplyr::everything()) %>%
      dplyr::rename_with(~ gsub("_mu$", "", .), dplyr::everything()) %>%
      dplyr::rename_with(~ gsub("omega_3", "omega-3", .), dplyr::everything()) %>%
      dplyr::rename_with(~ gsub("vitamin_a", "vitamin-A", .), dplyr::everything())
  }
}

Aim

This report is automatically generated in the last step of Peskas' data pipeline and summarises the main statistics and insights related to small-scale fisheries (SSF) in Timor-Leste. The report gives an overview of the Peskas' fleet and provide aggregated statistics and time series of the total revenue and total catch. The report provide also information on the catch composition, highlighting the most important fish groups in terms of overall stock.

\pagebreak

Data distribution

kobo_trips %>%
  dplyr::select(landing_id, landing_date, municipality) %>%
  tidyr::complete(municipality, landing_date) %>%
  dplyr::mutate(
    record = ifelse(is.na(landing_id), 0, 1),
    landing_date = lubridate::floor_date(landing_date, unit = "month")
  ) %>%
  dplyr::group_by(municipality, landing_date) %>%
  dplyr::summarise(obs = sum(record)) %>%
  dplyr::filter(!is.na(municipality)) %>%
  ggplot(aes(landing_date, reorder(municipality, obs),
    fill = sqrt(obs + 1),
    color = sqrt(obs + 1)
  )) +
  theme_minimal() +
  geom_tile(width = 30) +
  coord_cartesian(expand = FALSE) +
  scale_fill_gradientn(colours = c("white", "#a4c3c8", "#7fa5a9", "#35666f", "#103235")) +
  scale_color_gradientn(colours = c("white", "#a4c3c8", "#7fa5a9", "#35666f", "#103235")) +
  theme(
    panel.grid = element_blank(),
    legend.position = "bottom"
  ) +
  labs(y = "", x = "Date", fill = "N. surveys\nper month") +
  guides(color = "none")

Fishery profile

This section contains information of the Timor-Leste SSF' fleet and the main characteristics of the fishing trips. The information is based on the data collected during the Peskas' surveys.

Boats information

metadata$boats %>%
  dplyr::select(.data$boat_length, .data$boat_engine_power) %>%
  tidyr::pivot_longer(cols = tidyr::everything()) %>%
  dplyr::mutate(value = as.numeric(value)) %>% 
  ggplot() +
  theme_minimal(12) +
  facet_grid(. ~ name,
    scales = "free",
    labeller = as_labeller(c(
      boat_engine_power = "Boat horspower (hp)",
      boat_length = "Boat length (m)"
    ))
  ) +
  geom_histogram(mapping = aes(x = value), bins = 30, binwidth = 0.5, fill = "#447597", alpha = 0.5) +
  scale_x_continuous(n.breaks = 10) +
  theme(
    text = element_text(family = "Helvetica"),
    plot.subtitle = element_text(size = 9, color = "darkslategrey"),
    panel.grid = element_blank()
  ) +
  labs(
    x = "",
    y = "N. observations"
  )

Gear used and boats type

my_palette <- c(
  "#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", "#FF7F00",
  "#cccc28", "#A65628", "#F781BF", "#999999", "#66C2A5",
  "#FC8D62", "#00BFFF", "#808000"
)


p1 <-
  kobo_trips %>%
  dplyr::filter(!is.na(gear) & !is.na(municipality)) %>%
  dplyr::select(landing_id, municipality, gear) %>%
  dplyr::group_by(municipality) %>%
  dplyr::mutate(tot_obs = dplyr::n()) %>%
  dplyr::group_by(municipality, gear) %>%
  dplyr::summarise(
    tot_obs = dplyr::first(tot_obs),
    n = dplyr::n()
  ) %>%
  dplyr::ungroup() %>%
  tidyr::complete(municipality, gear) %>%
  tidyr::replace_na(replace = list(n = 0)) %>%
  dplyr::arrange(-tot_obs) %>%
  apexcharter::apex(
    type = "bar",
    mapping = apexcharter::aes(x = municipality, y = n, fill = gear),
    height = 500
  ) %>%
  apexcharter::ax_chart(
    stacked = TRUE,
    stackType = "100%"
  ) %>%
  apexcharter::ax_colors(my_palette) %>%
  apexcharter::ax_xaxis(
    title = list(
      text = "N. surveys"
    )
  ) %>%
  apexcharter::ax_labs(
    subtitle = "Gear type proportion by region"
  )

p2 <-
  kobo_trips %>%
  dplyr::filter(!is.na(propulsion_gear) & !is.na(municipality)) %>%
  dplyr::select(landing_id, municipality, propulsion_gear) %>%
  dplyr::group_by(municipality) %>%
  dplyr::mutate(tot_obs = dplyr::n()) %>%
  dplyr::group_by(municipality, propulsion_gear) %>%
  dplyr::summarise(
    tot_obs = dplyr::first(tot_obs),
    n = dplyr::n()
  ) %>%
  dplyr::ungroup() %>%
  tidyr::complete(municipality, propulsion_gear) %>%
  tidyr::replace_na(replace = list(n = 0)) %>%
  dplyr::arrange(-tot_obs) %>%
  apexcharter::apex(
    type = "bar",
    mapping = apexcharter::aes(x = municipality, y = n, fill = propulsion_gear),
    height = 500
  ) %>%
  apexcharter::ax_chart(
    stacked = TRUE
  ) %>%
  apexcharter::ax_colors(my_palette) %>%
  apexcharter::ax_xaxis(
    title = list(
      text = "N. surveys"
    )
  ) %>% 
    apexcharter::ax_labs(
    subtitle = "Surveys by vessel type"
  )


apexcharter::apex_grid(
  p1, p2,
  grid_area = c("1 / 1 / 3 / 2", "1 / 2 / 2 / 4"),
  ncol = 2,
  nrow = 1,
  height = "600px"
)

\pagebreak

Fishery indicators

This section contains information on the main fishery indicators, including the number of trips, the catch volume, the fishing effort and the fishing revenue at national and municipal level. The information is based on the data collected during the Peskas' surveys.

Catch per unit effort

Catch per unit effort (CPUE) is a measure of the productivity of a fishery. It is calculated as the total catch divided by the total fishing effort. The fishing effort is expressed as the number of fishers multiplied by the duration of the fishing trip. The CPUE is expressed in kg per fisher per hour.

kobo_trips %>%
  dplyr::select(
    .data$landing_id,
    .data$landing_date,
    .data$trip_length,
    dplyr::starts_with("fisher_number"), .data$landing_catch
  ) %>%
  dplyr::mutate(
    landing_period = lubridate::floor_date(.data$landing_date, unit = "month"),
    landing_id = as.character(.data$landing_id),
    n_fishers = fisher_number_child + fisher_number_man + fisher_number_woman
  ) %>%
  dplyr::select(-dplyr::starts_with("fisher_number")) %>%
  tidyr::unnest(.data$landing_catch) %>%
  tidyr::unnest(.data$length_frequency) %>%
  dplyr::filter(!is.na(.data$catch)) %>%
  dplyr::group_by(.data$landing_id) %>%
  dplyr::summarise(
    landing_date = dplyr::first(.data$landing_date),
    landing_period = dplyr::first(.data$landing_period),
    trip_length = dplyr::first(.data$trip_length),
    n_fishers = dplyr::first(.data$n_fishers),
    catch = sum(.data$catch, na.rm = T)
  ) %>%
  dplyr::mutate(
    cpue = catch / (n_fishers / trip_length),
    cpue = ifelse(is.infinite(cpue), NA, cpue),
    cpue = cpue / 1000
  ) %>% 
  dplyr::select(landing_period, cpue) %>%
  dplyr::group_by(landing_period) %>%
  dplyr::summarise(
    mean = median(cpue, na.rm = TRUE),
    sd = sd(cpue, na.rm = TRUE),
    n = dplyr::n()
  ) %>%
  dplyr::mutate(
    se = sd / sqrt(n),
    ic = se * qt((1 - 0.05) / 2 + .5, n - 1)
  ) %>%
  ggplot(aes(as.Date(landing_period), mean)) +
  geom_line(color = "#447597") +
  geom_point(color = "#447597") +
  geom_area(fill = "#447597", alpha = 0.15) +
  theme_minimal(14) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_date(
    date_breaks = "4 month", minor_breaks = NULL, labels = label_date,
    limits = c(as.Date("2018-01-01"), Sys.Date() - 31)
  ) +
  theme(
    panel.grid = element_blank(),
    text = element_text(family = "Helvetica"),
    plot.title = element_text(size = 18),
    plot.subtitle = element_text(size = 12, color = "darkslategrey")
  ) +
  labs(
    x = "Date", y = "Catch per unit effort (kg / fisher-hour)",
    #title = "Interannual distribution of fishing effort",
    subtitle = "Monthly median fishing effort expressed as catch (kg) per fisher per hour"
  )

Number of trips

estimates$national$aggregated %>%
  ggplot(aes(landing_period, n_landings_per_boat)) +
  geom_line(color = "#447597") +
  geom_point(color = "#447597") +
  geom_area(fill = "#447597", alpha = 0.25) +
  # geom_area(fill="#447597",alpha=0.15)+
  stat_smooth(method = "loess", color = "#976644", alpha = 0.1, size = 0.5) +
  labs(
    x = "Date",
    y = "Fishing trips",
    subtitle = "Average of fishing trips per boat per month"
  ) +
  scale_x_date(
    date_breaks = "4 month", minor_breaks = NULL, labels = label_date,
    limits = c(as.Date("2018-01-01"), Sys.Date() - 31)
  ) +
  scale_y_continuous(labels = scales::comma) +
  theme_minimal(14) +
  theme(
    panel.grid = element_blank(),
    text = element_text(family = "Helvetica"),
    plot.title = element_text(size = 18),
    plot.subtitle = element_text(size = 12, color = "darkslategrey")
  )+
  coord_cartesian(ylim = c(min(9), NA),expand = FALSE)

Catch volume National

estimates$national$aggregated %>%
  ggplot(aes(landing_period, catch / 1000)) +
  geom_line(color = "#447597") +
  geom_point(color = "#447597") +
  geom_area(fill = "#447597", alpha = 0.25) +
  # geom_area(fill="#447597",alpha=0.15)+
  stat_smooth(method = "loess", color = "#976644", alpha = 0.1, size = 0.5) +
  labs(
    x = "Date", y = "Monthly catch (tons)"
  ) +
  scale_x_date(
    date_breaks = "4 month", minor_breaks = NULL, labels = label_date,
    limits = c(as.Date("2018-01-01"), Sys.Date() - 31)
  ) +
  scale_y_continuous(labels = scales::comma) +
  theme_minimal(14) +
  theme(
    panel.grid = element_blank(),
    text = element_text(family = "Helvetica"),
    plot.title = element_text(size = 18),
    plot.subtitle = element_text(size = 12, color = "darkslategrey")
  )+
  coord_cartesian(expand = FALSE)

Catch volume Municipal

estimates$municipal %>%
  purrr::map(~ purrr::keep(.x, stringr::str_detect(
    names(.x), stringr::fixed("aggregated")
  ))) %>%
  purrr::flatten() %>%
  purrr::set_names(names(estimates$municipal)) %>%
  dplyr::bind_rows(.id = "reporting_region") %>%
  dplyr::left_join(vessels_stats, by = "reporting_region") %>%
  ggplot(aes(landing_period, catch / 1000)) +
  facet_wrap(~reporting_region, ncol = 3, scales = "free") +
  geom_line(color = "#447597") +
  geom_point(aes(color = is_imputed)) +
  geom_area(fill = "#447597", alpha = 0.15) +
  stat_smooth(method = "loess", color = "#976644", alpha = 0.1, size = 0.5) +
  labs(x = "Date", y = "Catch volume (tons)") +
  scale_y_continuous(labels = scales::comma) +
  scale_color_manual(values = c("#505050", "#d23f67")) +
  theme_minimal() +
  theme(
    panel.grid.minor.x = element_blank(),
    text = element_text(family = "Helvetica"),
    plot.title = element_text(size = 18),
    plot.subtitle = element_text(size = 12, color = "darkslategrey")
  ) +
  guides(color = "none")

Fishing revenue National

estimates$national$aggregated %>%
  ggplot(aes(landing_period, catch_price)) +
  geom_line(color = "#447597") +
  geom_point(color = "#447597") +
  geom_area(fill = "#447597", alpha = 0.25) +
  # geom_area(fill="#447597",alpha=0.15)+
  stat_smooth(method = "loess", color = "#976644", alpha = 0.1, size = 0.5) +
  labs(
    x = "Date", y = "Monthly revenue (USD)"
  ) +
  scale_x_date(
    date_breaks = "4 month", minor_breaks = NULL, labels = label_date,
    limits = c(as.Date("2018-01-01"), Sys.Date() - 31)
  ) +
  scale_y_continuous(labels = scales::comma) +
  theme_minimal(14) +
  theme(
    panel.grid = element_blank(),
    text = element_text(family = "Helvetica"),
    plot.title = element_text(size = 18),
    plot.subtitle = element_text(size = 12, color = "darkslategrey")
  )+
  coord_cartesian(expand = FALSE)

Fishing revenue Municipal

estimates$municipal %>%
  purrr::map(~ purrr::keep(.x, stringr::str_detect(
    names(.x), stringr::fixed("aggregated")
  ))) %>%
  purrr::flatten() %>%
  purrr::set_names(names(estimates$municipal)) %>%
  dplyr::bind_rows(.id = "reporting_region") %>%
  dplyr::left_join(vessels_stats, by = "reporting_region") %>%
  ggplot(aes(landing_period, catch_price)) +
  facet_wrap(~reporting_region, ncol = 3, scales = "free") +
  geom_line(color = "#447597") +
  geom_point(aes(color = is_imputed)) +
  geom_area(fill = "#447597", alpha = 0.15) +
  stat_smooth(method = "loess", color = "#976644", alpha = 0.1, size = 0.5) +
  labs(x = "Date", y = "Revenue (USD)") +
  scale_y_continuous(labels = scales::comma) +
  scale_color_manual(values = c("#505050", "#d23f67")) +
  theme_minimal() +
  theme(
    panel.grid.minor.x = element_blank(),
    text = element_text(family = "Helvetica"),
    plot.title = element_text(size = 18),
    plot.subtitle = element_text(size = 12, color = "darkslategrey")
  ) +
  guides(color = "none")

Market value National

estimates$national$aggregated %>%
  ggplot(aes(landing_period, price_kg)) +
  geom_line(color = "#447597") +
  geom_point(color = "#447597") +
  geom_area(fill = "#447597", alpha = 0.25) +
  # geom_area(fill="#447597",alpha=0.15)+
  stat_smooth(method = "loess", color = "#976644", alpha = 0.1, size = 0.5) +
  labs(
    x = "Date", y = "Monthly price per kg (USD)"
  ) +
  scale_x_date(
    date_breaks = "4 month", minor_breaks = NULL, labels = label_date,
    limits = c(as.Date("2018-01-01"), Sys.Date() - 31)
  ) +
  scale_y_continuous(labels = scales::comma) +
  theme_minimal(14) +
  theme(
    panel.grid = element_blank(),
    text = element_text(family = "Helvetica"),
    plot.title = element_text(size = 18),
    plot.subtitle = element_text(size = 12, color = "darkslategrey")
  )+
  coord_cartesian(expand = FALSE)

Market value Municipal

estimates$municipal %>%
  purrr::map(~ purrr::keep(.x, stringr::str_detect(
    names(.x), stringr::fixed("aggregated")
  ))) %>%
  purrr::flatten() %>%
  purrr::set_names(names(estimates$municipal)) %>%
  dplyr::bind_rows(.id = "reporting_region") %>%
  dplyr::left_join(vessels_stats, by = "reporting_region") %>%
  ggplot(aes(landing_period, price_kg)) +
  facet_wrap(~reporting_region, ncol = 3, scales = "free") +
  geom_line(color = "#447597") +
  geom_point(aes(color = is_imputed)) +
  geom_area(fill = "#447597", alpha = 0.15) +
  stat_smooth(method = "loess", color = "#976644", alpha = 0.1, size = 0.5) +
  labs(x = "Date", y = "Price per kg") +
  scale_y_continuous(labels = scales::comma) +
  scale_color_manual(values = c("#505050", "#d23f67")) +
  theme_minimal() +
  theme(
    panel.grid.minor.x = element_blank(),
    text = element_text(family = "Helvetica"),
    plot.title = element_text(size = 18),
    plot.subtitle = element_text(size = 12, color = "darkslategrey")
  ) +
  guides(color = "none")

\pagebreak

Catch usage

This section contains information on the final catch usage, it is recorded as deemed for the market (sell), for self-sufficiency (food) or for both purposes.

species <- 
  metadata$catch_types %>% 
  dplyr::select(catch_taxon = interagency_code,
                catch_name_en) %>% 
  dplyr::filter(!catch_name_en %in%c("Herring", "Bannerfish", "Bannerfish"))

preplot <-
  kobo_trips %>%
  dplyr::select(
    .data$landing_id,
    .data$landing_catch
  ) %>%
  tidyr::unnest(.data$landing_catch) %>%
  tidyr::unnest(.data$length_frequency) %>%
  dplyr::filter(!is.na(.data$catch)) %>%
  dplyr::group_by(.data$landing_id, .data$catch_taxon) %>%
  dplyr::summarise(
    catch_use = dplyr::first(.data$catch_use),
    catch = sum(.data$catch, na.rm = T),
  ) %>%
  dplyr::filter(!catch_taxon %in% ("0")) %>%
  dplyr::group_by(.data$catch_taxon, catch_use) %>%
  dplyr::summarise(
    obs = dplyr::n()
  ) %>%
  dplyr::group_by(.data$catch_taxon) %>%
  dplyr::mutate(tot_obs = sum(obs, na.rm = T)) %>%
  dplyr::mutate(prop_obs = obs / tot_obs) %>% 
  dplyr::ungroup()

preplot %>% 
  dplyr::left_join(species, by = "catch_taxon") %>% 
  ggplot(aes(x = reorder(catch_name_en, tot_obs), y = prop_obs, fill = catch_use)) +
  ggchicklet::geom_chicklet() +
  theme_minimal(10) +
  theme(
    legend.position = "bottom",
    panel.grid = element_blank(),
    plot.subtitle = element_text(color = "darkslategrey")
  ) +
  labs(
    y = "", x = "", fill = "Catch usage",
    subtitle = "Proportion of observations by catch purpose"
  ) +
  scale_fill_manual(values = catch_use_palette) +
  coord_flip()

Catch usage by municipality

species <- 
  metadata$catch_types %>% 
  dplyr::select(catch_taxon = interagency_code,
                catch_name_en) %>% 
  dplyr::filter(!catch_name_en %in%c("Herring", "Bannerfish", "Bannerfish"))

preplot <-
  kobo_trips %>%
  dplyr::select(
    .data$landing_id,
    .data$municipality,
    .data$landing_catch
  ) %>%
  tidyr::unnest(.data$landing_catch) %>%
  tidyr::unnest(.data$length_frequency) %>%
  dplyr::filter(!is.na(.data$catch)) %>%
  dplyr::group_by(.data$landing_id, .data$municipality, .data$catch_taxon) %>%
  dplyr::summarise(
    catch_use = dplyr::first(.data$catch_use),
    catch = sum(.data$catch, na.rm = T),
  ) %>%
  dplyr::filter(!catch_taxon %in% ("0")) %>%
  dplyr::group_by(.data$municipality, catch_use) %>%
  dplyr::summarise(
    obs = dplyr::n()
  ) %>%
  dplyr::group_by(.data$municipality) %>%
  dplyr::mutate(tot_obs = sum(obs, na.rm = T)) %>%
  dplyr::mutate(prop_obs = obs / tot_obs) %>% 
  dplyr::ungroup()

preplot %>% 
  dplyr::filter(!is.na(municipality)) %>%
  #dplyr::left_join(species, by = "catch_taxon") %>% 
  ggplot(aes(x = reorder(municipality, tot_obs), y = prop_obs, fill = catch_use)) +
  ggchicklet::geom_chicklet() +
  theme_minimal(9) +
  theme(
    legend.position = "bottom",
    panel.grid = element_blank(),
    plot.subtitle = element_text(color = "darkslategrey")
  ) +
  labs(
    y = "", x = "", fill = "Catch usage",
    subtitle = "Overall catch purpose by municipality"
  ) +
  scale_fill_manual(values = catch_use_palette) +
  coord_flip()

\pagebreak

Catch composition

this section contains information on the catch composition, highlighting the most important fish groups in terms of overall stock. The information is based on the data collected during the Peskas' surveys.

cols <- c("#ffffff", "#f2fbd2", "#c9ecb4", "#93d3ab", "#35b0ab")

species <-
  metadata$catch_types %>%
  dplyr::select(
    grouped_taxa = interagency_code,
    grouped_taxa_names = catch_name_en
  ) %>%
  dplyr::filter(!grouped_taxa_names %in% c("Herring", "Bannerfish", "Bannerfish"))


images <- c(
  "https://storage.googleapis.com/public-timor/SAR.svg",
  "https://storage.googleapis.com/public-timor/GAR.svg",
  "https://storage.googleapis.com/public-timor/TUN.svg",
  "https://storage.googleapis.com/public-timor/MAC.svg",
  "https://storage.googleapis.com/public-timor/FLYFI.svg",
  "https://storage.googleapis.com/public-timor/SNA.svg",
  "https://storage.googleapis.com/public-timor/MOO.svg",
  "https://storage.googleapis.com/public-timor/JAC.svg",
  "https://storage.googleapis.com/public-timor/FUS.svg",
  "https://storage.googleapis.com/public-timor/NEE.svg",
  "https://storage.googleapis.com/public-timor/SHM.svg",
  "https://storage.googleapis.com/public-timor/JOB.svg",
  "https://storage.googleapis.com/public-timor/OTHR.svg"
)

t_format <- function(value) {
  paste0(value, " t")
}


tab <-
  estimates$municipal %>%
  purrr::map(~ purrr::keep(.x, stringr::str_detect(
    names(.x), stringr::fixed("taxa")
  ))) %>%
  purrr::flatten() %>%
  purrr::set_names(names(estimates$municipal)) %>%
  dplyr::bind_rows(.id = "region") %>%
  dplyr::select(landing_period, catch, grouped_taxa) %>%
  dplyr::mutate(year = data.table::year(landing_period)) %>%
  dplyr::group_by(year, grouped_taxa) %>%
  dplyr::summarise(catch = sum(catch)) %>%
  dplyr::ungroup() %>%
  tidyr::complete(grouped_taxa) %>%
  dplyr::left_join(species, by = "grouped_taxa") %>%
  dplyr::select(year, catch, grouped_taxa_names, grouped_taxa) %>%
  dplyr::mutate(grouped_taxa_names = factor(grouped_taxa_names, levels = c(
    "Sardines/pilchards",
    "Garfish",
    "Tuna/Bonito/Other Mackerel",
    "Mackerel scad",
    "Flying fish",
    "Snapper/seaperch",
    "Moonfish",
    "Jacks/Trevally/Other Scad",
    "Fusilier",
    "Long tom",
    "Short bodied mackerel",
    "Jobfish",
    "Other"
  ))) %>%
  dplyr::arrange(grouped_taxa_names) %>% 
  dplyr::arrange(grouped_taxa_names) %>%
  dplyr::ungroup() %>%
  dplyr::mutate(catch = round(catch, 2) / 1000) %>%
  dplyr::filter(!is.na(year)) %>%
  tidyr::pivot_wider(names_from = year, values_from = catch) %>%
  dplyr::rowwise() %>%
  dplyr::mutate(ts = list(c(`2018`, `2019`, `2020`, `2021`, `2022`, `2023`, `2024`))) %>%
  dplyr::ungroup() %>%
  dplyr::filter(!grouped_taxa_names == c("Unknown")) %>%
  dplyr::mutate(
    urls = images,
    dplyr::across(dplyr::where(is.numeric), ~ round(.x, 2))
  ) %>%
  dplyr::select(grouped_taxa_names, urls, dplyr::everything()) %>%
  dplyr::select(-grouped_taxa)

tab %>%
  dplyr::select(-.data$ts) %>%
  reactable::reactable(
    theme = reactablefmtr::fivethirtyeight(centered = T, cell_padding = 0),
    pagination = FALSE,
    compact = FALSE,
    borderless = TRUE,
    striped = FALSE,
    fullWidth = TRUE,
    sortable = TRUE,
    height = 500,
    defaultColDef = reactable::colDef(
      align = "center"
    ),
    columns = list(
      grouped_taxa_names = reactable::colDef(
        name = "Taxa",
        minWidth = 110
      ),
      "2018" = reactable::colDef(
        minWidth = 90,
        format = reactable::colFormat(separators = TRUE),
        style = reactablefmtr::color_scales(., colors = cols, opacity = 0.75),
        cell = t_format
      ),
      "2019" = reactable::colDef(
        minWidth = 90,
        format = reactable::colFormat(separators = TRUE),
        style = reactablefmtr::color_scales(., colors = cols, opacity = 0.75),
        cell = t_format
      ),
      "2020" = reactable::colDef(
        minWidth = 90,
        format = reactable::colFormat(separators = TRUE),
        style = reactablefmtr::color_scales(., colors = cols, opacity = 0.75),
        cell = t_format
      ),
      "2021" = reactable::colDef(
        minWidth = 90,
        format = reactable::colFormat(separators = TRUE),
        style = reactablefmtr::color_scales(., colors = cols, opacity = 0.75),
        cell = t_format
      ),
      "2022" = reactable::colDef(
        minWidth = 90,
        format = reactable::colFormat(separators = TRUE),
        style = reactablefmtr::color_scales(., colors = cols, opacity = 0.75),
        cell = t_format
      ),
      "2023" = reactable::colDef(
        minWidth = 90,
        format = reactable::colFormat(separators = TRUE),
        style = reactablefmtr::color_scales(., colors = cols, opacity = 0.75),
        cell = t_format
      ),
      urls = reactable::colDef(
        name = "",
        minWidth = 120,
        # footer = i18n_r()$t(pars$composition$table$footer$text),
        footerStyle = list(fontWeight = "lighter"),
        format = reactable::colFormat(separators = TRUE),
        cell = reactablefmtr::embed_img(
          height = 60,
          width = 95
        )
      ),
      ts = reactable::colDef(
        name = "Time Series",
        minWidth = 250,
        cell = reactablefmtr::react_sparkline(
          .,
          height = 80,
          line_color = "#00939d",
          line_width = 2,
          statline = "mean",
          statline_color = "#9d0a00",
          statline_label_size = "0.9em",
          area_opacity = 0.1,
          show_area = TRUE,
          tooltip_type = 1
        )
      )
    )
  )



species <- 
  metadata$catch_types %>%
  dplyr::select(
    catch_taxon = interagency_code,
    comm_name = catch_name_en
  ) %>% 
  dplyr::filter(!comm_name %in% c("Herring", "Bannerfish", "Bannerfish"))


estimates$national$taxa %>%
  dplyr::rename(catch_taxon = grouped_taxa) %>%
  dplyr::left_join(species, by = "catch_taxon") %>%
  dplyr::filter(catch_taxon %in% c("CLP", "GZP", "TUN","SDX")) %>%
  dplyr::select(comm_name, landing_period, catch) %>%
  dplyr::group_by(landing_period, comm_name) %>%
  dplyr::summarise(catch = sum(catch, na.rm = TRUE)) %>%
  dplyr::mutate(comm_name = dplyr::case_when(
    comm_name == "Sardines/pilchards" ~ "Sardines",
    comm_name == "Tuna/Bonito/Other Mackerel" ~ "Tuna/Bonito",
    TRUE ~ comm_name
  )) %>%
  dplyr::mutate(comm_name = factor(comm_name, levels = c(
    "Sardines",
    "Garfish",
    "Tuna/Bonito",
    "Mackerel scad"))) %>% 
  ggplot(aes(x = landing_period, y = catch / 1000)) +
  facet_grid(comm_name ~ ., scales = "free_y") +
  geom_line(aes(color = comm_name), show.legend = FALSE) +
  geom_area(aes(fill = comm_name), alpha = 0.5) +
  scale_x_date(
    date_breaks = "4 month", minor_breaks = NULL, labels = label_date,
    limits = c(as.Date("2018-01-01"), Sys.Date() - 31)
  ) +
  scale_y_continuous(labels = scales::comma, limits = c(0, NA)) +
  scale_color_manual(values = c("#50514f", "#cbd4c2", "#07004d", "#247ba0")) +
  scale_fill_manual(values = c("#50514f", "#cbd4c2", "#07004d", "#247ba0")) +
  theme_minimal() +
  theme(
    panel.grid = element_blank(),
    text = element_text(family = "Helvetica"),
    legend.position = "bottom",
    plot.title = element_text(size = 18),
    plot.subtitle = element_text(size = 13, color = "darkslategrey")
  ) +
  labs(
    x = "Date", y = "Tonnes live catch",
    color = "Fish group",
    fill = "",
    subtitle = "Time series of total live catch by most important fish groups."
  )

Catch composition by municipality

species <- 
  metadata$catch_types %>% 
  dplyr::select(grouped_taxa = interagency_code,
                catch_name_en) %>% 
  dplyr::filter(!catch_name_en %in%c("Herring", "Bannerfish", "Bannerfish", "Unknown"))


estimates$municipal %>%
  purrr::map(~ purrr::keep(.x, stringr::str_detect(
    names(.x), stringr::fixed("taxa")
  ))) %>%
  purrr::flatten() %>%
  purrr::set_names(names(estimates$municipal)) %>%
  dplyr::bind_rows(.id = "reporting_region") %>%
  dplyr::left_join(vessels_stats, by = "reporting_region") %>% 
  dplyr::group_by(reporting_region, grouped_taxa) %>%
  dplyr::summarise(catch = sum(catch, na.rm = T)) %>%
  dplyr::ungroup() %>% 
  dplyr::left_join(species, by = "grouped_taxa") %>% 
  dplyr::select(-grouped_taxa) %>%
  tidyr::complete(reporting_region, catch_name_en, fill = list(catch = 0)) %>%
  # Calculate the total catch per municipality
  dplyr::group_by(reporting_region) %>%
  dplyr::mutate(total_catch = sum(catch)) %>%
  # Calculate the percentage of catch for each grouped_taxa within each municipality
  dplyr::mutate(percent_catch = (catch / total_catch) * 100) %>%
  dplyr::ungroup() %>%
  # Plot with ggplot2 using percent_catch
  ggplot(aes(x = reorder(reporting_region, total_catch), y = percent_catch, fill = catch_name_en)) +
  #geom_col() +
  ggchicklet::geom_chicklet() +
  theme_minimal() +
  theme(
    legend.position = "right",
    panel.grid = element_blank(),
    plot.subtitle = element_text(color = "darkslategrey")
  ) +
  scale_fill_viridis_d(alpha = 0.70, option = "turbo")+
  coord_flip()+
  labs(x = "", y = "Percent of catch", fill = "Fish group")

Gender composition

This section provides details on the gender breakdown and gender-specific activities in Timor-Leste's small-scale fisheries (SSF).

library(ggforce)

dat <- 
  kobo_trips %>%
  dplyr::select(
    .data$landing_id,
    .data$habitat,
    .data$gear,
    dplyr::starts_with("fisher_number"),
    .data$landing_catch
  ) %>%
  tidyr::unnest(.data$landing_catch) %>%
  tidyr::unnest(.data$length_frequency) %>%
  dplyr::filter(!is.na(.data$catch)) %>%
  dplyr::group_by(.data$landing_id, .data$catch_taxon) %>%
  dplyr::summarise(
    habitat = dplyr::first(habitat),
    gear = dplyr::first(gear),
    fisher_number_child = dplyr::first(fisher_number_child),
    fisher_number_man = dplyr::first(fisher_number_man),
    fisher_number_woman = dplyr::first(fisher_number_woman),
    catch_use = dplyr::first(catch_use),
    catch = sum(.data$catch, na.rm = T)
  ) %>% 
  dplyr::filter(!is.na(fisher_number_child),!is.na(fisher_number_woman),!is.na(fisher_number_man))

parallel_plot <- 
  dat %>% 
  dplyr::filter(!is.na(habitat), !is.na(gear)) %>% 
  dplyr::group_by(landing_id) %>% 
  dplyr::summarise(habitat = dplyr::first(habitat),
                   gear = dplyr::first(gear),
                   fisher_number_child = dplyr::first(fisher_number_child),
                   fisher_number_man = dplyr::first(fisher_number_man),
                   fisher_number_woman = dplyr::first(fisher_number_woman)) %>% 
  dplyr::select(habitat, gear, fisher_number_woman, fisher_number_child, fisher_number_man) %>% 
  tidyr::pivot_longer(-c(habitat, gear)) %>% 
  dplyr::group_by(habitat, gear, name) %>% 
  dplyr::summarise(value = sum(value)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(dplyr::across(habitat:name, ~ as.factor(.x))) %>% 
  dplyr::mutate(name = dplyr::case_when(name == "fisher_number_child" ~ "Childs",
                                        name == "fisher_number_woman" ~ "Women",
                                        name == "fisher_number_man" ~ "Men"),
                name = as.factor(name)) %>% 
  dplyr::rename("Gender" = name,
                "Habitat" = habitat,
                "Gear type" = gear) %>% 
  ggforce::gather_set_data(c(3,1,2))

parallel_plot$x <- factor(parallel_plot$x, levels = c("3", "1", "2"),
                          labels = c("Gender","Habitat", "Gear type"))

parallel_plot$y <- factor(parallel_plot$y, levels = c("Men","Childs","Women",
                                                      "Deep", "Reef", "FAD", "Beach", "Traditional FAD", "Mangrove", "Seagrass",
                                                      "gill net", "long line", "hand line","seine net", "spear gun","manual collection",
                                                      "beach seine", "cast net", "trap"))


parallel_plot %>% 
  na.omit() %>%
  ggplot(aes(x, id = id, split = y, value = value)) +
  geom_parallel_sets(aes(fill = Gender), alpha = 0.75, axis.width = 0.1) +
  geom_parallel_sets_axes(axis.width = 0.25, fill = "grey85", color = "black", size = 0.1) +
  geom_parallel_sets_labels(colour = "black", angle = 0, size = 3.5) +
  scale_x_discrete(name = NULL, expand = c(0, 0.2)) +
  scale_y_continuous(breaks = NULL, expand = c(0.05,0)) +
  theme_minimal(12) +
  scale_fill_manual(values = c("#508AA8", "grey90", "#BD9391"))+
  theme(
    axis.line = element_blank(),
    axis.ticks = element_blank(),
    legend.position = "bottom",
    panel.grid.major = element_blank(),
    axis.text = element_text(size = 12, color ="black")
  ) +
  labs(fill = "")
p1 <- 
  dat %>% 
  dplyr::group_by(landing_id) %>% 
  dplyr::summarise(habitat = dplyr::first(habitat),
                   gear = dplyr::first(gear),
                   fisher_number_child = dplyr::first(fisher_number_child),
                   fisher_number_man = dplyr::first(fisher_number_man),
                   fisher_number_woman = dplyr::first(fisher_number_woman),
                   catch_use = dplyr::first(catch_use)) %>% 
  dplyr::mutate(category = dplyr::case_when(fisher_number_man == 0  ~ "Women and childs",
                                            TRUE ~ "Only men")) %>% 
  dplyr::group_by(habitat, category) %>% 
  dplyr::count() %>% 
  dplyr::arrange(dplyr::desc(n)) %>% 
  dplyr::group_by(category) %>% 
  na.omit() %>% 
  dplyr::mutate(n_tot = sum(n, na.rm = T),
                n = round(n/n_tot*100,2)) %>% 
  ggplot(aes(area = n, fill = habitat,
             label = paste(habitat, paste0(n, " %"), sep = "\n"))) +
  theme_minimal()+
  facet_grid(.~category) +
  scale_fill_brewer(palette = "Paired")+
  scale_color_brewer(palette = "Paired")+
  treemapify::geom_treemap(aes(color = habitat), alpha = 0.75, size = 2) +
  treemapify::geom_treemap_text(colour = "black",
                                place = "centre",
                                size = 13)+
  labs(title = "Habitat exploited")+
  theme(legend.position = "")

p2 <- 
  dat %>% 
  dplyr::group_by(landing_id) %>% 
  dplyr::summarise(habitat = dplyr::first(habitat),
                   gear = dplyr::first(gear),
                   fisher_number_child = dplyr::first(fisher_number_child),
                   fisher_number_man = dplyr::first(fisher_number_man),
                   fisher_number_woman = dplyr::first(fisher_number_woman),
                   catch_use = dplyr::first(catch_use)) %>% 
  dplyr::mutate(category = dplyr::case_when(fisher_number_man == 0  ~ "Women and childs",
                                            TRUE ~ "Only men")) %>% 
  dplyr::group_by(gear, category) %>% 
  dplyr::count() %>% 
  dplyr::arrange(dplyr::desc(n)) %>% 
  dplyr::group_by(category) %>% 
  na.omit() %>% 
  dplyr::mutate(n_tot = sum(n, na.rm = T),
                n = round(n/n_tot*100,2)) %>% 
  ggplot(aes(area = n, fill = gear,
             label = paste(gear, paste0(n, " %"), sep = "\n"))) +
  theme_minimal()+
  facet_grid(.~category) +
  scale_fill_brewer(palette = "Dark2")+
  scale_color_brewer(palette = "Dark2")+
  treemapify::geom_treemap(aes(color = gear), alpha = 0.65, size = 2) +
  treemapify::geom_treemap_text(colour = "black",
                                place = "centre",
                                size = 13)+
  labs(title = "Gear used")+
  theme(legend.position = "")

p3 <- 
  dat %>% 
  dplyr::group_by(landing_id) %>% 
  dplyr::summarise(habitat = dplyr::first(habitat),
                   gear = dplyr::first(gear),
                   fisher_number_child = dplyr::first(fisher_number_child),
                   fisher_number_man = dplyr::first(fisher_number_man),
                   fisher_number_woman = dplyr::first(fisher_number_woman),
                   catch_use = dplyr::first(catch_use)) %>% 
  dplyr::mutate(category = dplyr::case_when(fisher_number_man == 0  ~ "Women and childs",
                                            TRUE ~ "Only men")) %>% 
  dplyr::group_by(catch_use, category) %>% 
  dplyr::count() %>% 
  dplyr::arrange(dplyr::desc(n)) %>% 
  dplyr::group_by(category) %>% 
  na.omit() %>% 
  dplyr::mutate(n_tot = sum(n, na.rm = T),
                n = round(n/n_tot*100,2)) %>% 
  ggplot(aes(area = n, fill = catch_use,
             label = paste(catch_use, paste0(n, " %"), sep = "\n"))) +
  theme_minimal()+
  facet_grid(.~category) +
  scale_fill_manual(values = c("#bce784", "#ba9790", "#91b7c7"))+
  scale_color_manual(values = c("#bce784", "#ba9790", "#91b7c7"))+
  treemapify::geom_treemap(aes(color = catch_use),alpha = 0.7, size = 2) +
  treemapify::geom_treemap_text(colour = "black",
                                place = "centre",
                                size = 13)+
  labs(title = "Catch final usage")+
  theme(legend.position = "")

cowplot::plot_grid(p1,p2,p3, ncol = 1)

Boat tracking

Boat movements are tracked by Pelagic Data System tracking system, and a proprietary algorithm is used to determine when a trip occurs. Tracks are recorded by GPS devices mounted on the boats. The heatmap refer to the boats' movements tracked along the Timor coast with a grid resolution of 10 x 10 meters. The tracks are filtered for outliers and some potential algorithm errors. Specifically, we do not take into account geo-referenced tracks characterized by large anomalies in the quality of the tracking signal, the speed of the boats, and the distance and time travelled.

htmltools::tags$iframe(
  src = "https://storage.googleapis.com/public-timor/kepler_pds_map.html",
  width = "100%",
  height = "500px",
  style = "border: none;"
)

Nutritional properties

The nutritional values for each catch were obtained by integrating the weight estimates for each fish-group retrieved from FishBase with modelled concentrations of seven nutrients [@hicks2019] foundable in FishBase Nutrient Research Tool and in the public repository associated to the paper on GitHub. In the plots below we refer to the Recommended Daily Intake of a woman between 15 and 49 years old [@Trumbo2002] to estimate the overall nutritional value.

catch_groups_name <-
  metadata$catch_types %>%
  dplyr::select(
    interagency_code,
    catch_name = catch_name_en
  ) %>%
  dplyr::filter(!catch_name %in% c("Herring", "Bannerfish", "Bannerfish"))

base_plot <-
  nutrients_table %>%
  dplyr::left_join(catch_groups_name) %>%
  dplyr::select(catch_name, Selenium_mu:Vitamin_A_mu) %>%
  rename_nutrients_mu(hyphen = FALSE) %>%
  tidyr::pivot_longer(-catch_name, names_to = "nutrient", values_to = "concentration") %>%
  dplyr::filter(!nutrient == "selenium" & !catch_name %in% "Other") %>%
  dplyr::left_join(RDI_tab) %>%
  dplyr::mutate(
    nutrient = stringr::str_to_title(nutrient),
    nutrient = dplyr::case_when(
      nutrient == "Omega3" ~ "Omega-3",
      nutrient == "Vitamina" ~ "Vitamin-A",
      TRUE ~ nutrient
    )
  ) %>%
  dplyr::mutate(rdi = (concentration * 100) / conv_factor) %>%
  dplyr::group_by(catch_name) %>%
  dplyr::mutate(tot = sum(rdi, na.rm = T)) %>%
  dplyr::arrange(-tot)

ggplot2::ggplot() +
  ggplot2::theme_bw() +
  ggchicklet::geom_chicklet(base_plot,
                            mapping = ggplot2::aes(
                              y = rdi, x = reorder(catch_name, tot),
                              fill = nutrient,
                              color = nutrient
                            ),
                            position = ggplot2::position_stack(reverse = FALSE),
                            alpha = 0.8,
                            width = 1
  ) +
  ggplot2::scale_fill_manual(values = nut_palette) +
  ggplot2::scale_color_manual(values = nut_palette) +
  ggplot2::scale_y_continuous(labels = scales::percent, n.breaks = 10) +
  ggplot2::labs(x = "", y = "Matched RNI from 100g portion", fill = "Nutrient") +
  ggplot2::theme(
    legend.position = "bottom",
    panel.grid = element_blank()
  ) +
  coord_flip(expand = FALSE, ylim = c(0, 1.55)) +
  guides(
    alpha = "none",
    color = "none"
  )
habitat_nutrients <- 
  kobo_trips %>%
  dplyr::select(
    .data$landing_id,
    .data$habitat,
    .data$landing_catch
  ) %>%
  tidyr::unnest(.data$landing_catch) %>%
  tidyr::unnest(.data$length_frequency) %>%
  dplyr::filter(!is.na(.data$catch)) %>%
  dplyr::select(habitat, catch:Vitamin_A_mu) %>%
  rename_nutrients_mu() %>%
  tidyr::pivot_longer(-c(habitat, catch), names_to = "nutrient") %>%
  dplyr::left_join(RDI_tab) %>%
  dplyr::mutate(
    value = value / catch,
    inds_kg = (value * 1000) / conv_factor
  ) %>%
  dplyr::group_by(habitat, nutrient) %>%
  dplyr::summarise(inds_kg = median(inds_kg, na.rm = T) / 10) %>%
  dplyr::mutate(inds_kg = inds_kg * 100) %>%
  dplyr::filter(!nutrient == "selenium") %>%
  dplyr::mutate(
    nutrient = stringr::str_to_title(nutrient),
    nutrient = dplyr::case_when(
      nutrient == "Omega3" ~ "Omega-3",
      nutrient == "Vitamina" ~ "Vitamin-A",
      TRUE ~ nutrient
    )
  )

  ggplot2::ggplot() +
  ggplot2::theme_bw(10) +
  ggchicklet::geom_chicklet(habitat_nutrients,
                            mapping = ggplot2::aes(
                              y = inds_kg,
                              x = reorder(habitat, inds_kg),
                              fill = nutrient,
                              color = nutrient
                            ),
                            position = ggplot2::position_stack(reverse = FALSE),
                            alpha = 0.8,
                            width = 0.8,
                            radius = grid::unit(3, "pt")
  ) +
  ggplot2::geom_text(habitat_nutrients,
                     mapping = ggplot2::aes(
                       y = inds_kg,
                       x = reorder(habitat, inds_kg),
                       label = round(inds_kg, 1),
                       group = nutrient
                     ),
                     position = ggplot2::position_stack(0.5, reverse = FALSE),
                     color = "white",
                     size = 3
  ) +
  ggplot2::scale_fill_manual(values = nut_palette) +
  ggplot2::scale_color_manual(values = nut_palette) +
  ggplot2::scale_y_continuous(labels = scales::label_percent(scale = 1)) +
  ggplot2::coord_flip(expand = FALSE) +
  ggplot2::theme(legend.position = "bottom",
                 panel.grid = element_blank()) +
  ggplot2::labs(x = "Habitat", fill = "Nutrient", y = "Matched RNI from 100g portion")+
  guides(
    alpha = "none",
    color = "none"
  )

About Peskas™

Peskas is the official fisheries national monitoring system of Timor-Leste and represents one of the most sophisticated data collection systems for small-scale fisheries in the world.

Peskas' platform collects real-time information directly from fishermen's activity via a system of digital surveys developed in KoBo toolbox. In addition, Peskas uses the technology provided by Pelagic Data System to record vessel movements via solar-powered tracking devices).

The data and the information collected is subjected to an elaborate processing and cleaning through an open-source code pipeline on GitHub, and provide important data in the hands of fisheries officers, researchers and local stakeholders and enables them to better understand the contribution of fish and fisheries to local livelihoods and food security.

Information about the process and user-centred design of the Peskas pipeline and initial analytics, and its application in fisheries research & management can be found in the following publications:

\pagebreak

References



WorldFishCenter/peskas.timor.data.pipeline documentation built on April 14, 2025, 1:47 p.m.