Workshop 2 Final Question

Author

Ryan Waln

Published

June 11, 2026

Introduction

This file is used to wrangle messy data on Ross River estuary fish surveys and produce final clean tables and figures to determine if fish species distributions are related to salinity

Steps include:

  • Reading in and inspecting data
  • Combining excel sheets
  • Standardizing text and dates across files
  • Dealing with NA values
  • Merging files together to insert scientific names and create master data sets
  • Reformatting larger data sets that constantly record data to fit with smaller ones that are only measured daily
  • Calculating SE for variables
  • Plotting professional figures

Housekeeping

Packages

library("tidyverse")
library("readxl") 

Read in data

estuary_metadata   <- read_csv(here::here("data", "workshop_2", "estuary_metadata.csv"))
estuary_sonde_data <- read_csv(here::here("data", "workshop_2","estuary_sonde_data.csv"))
species_dictionary <- read_csv(here::here("data", "workshop_2","species_dictionary.csv"))

Check site locations

estuary_metadata
# A tibble: 4 × 4
  site_name    lat   lon zone      
  <chr>      <dbl> <dbl> <chr>     
1 Upper_Ross -19.3  147. Upstream  
2 mid_ross   -19.3  147. Middle    
3 LOWER ROSS -19.3  147. Downstream
4 ross_mouth -19.2  147. Marine    
head(estuary_metadata)
# A tibble: 4 × 4
  site_name    lat   lon zone      
  <chr>      <dbl> <dbl> <chr>     
1 Upper_Ross -19.3  147. Upstream  
2 mid_ross   -19.3  147. Middle    
3 LOWER ROSS -19.3  147. Downstream
4 ross_mouth -19.2  147. Marine    
glimpse(estuary_metadata)
Rows: 4
Columns: 4
$ site_name <chr> "Upper_Ross", "mid_ross", "LOWER ROSS", "ross_mouth"
$ lat       <dbl> -19.31, -19.28, -19.26, -19.25
$ lon       <dbl> 146.74, 146.78, 146.81, 146.83
$ zone      <chr> "Upstream", "Middle", "Downstream", "Marine"
str(estuary_metadata)
spc_tbl_ [4 × 4] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ site_name: chr [1:4] "Upper_Ross" "mid_ross" "LOWER ROSS" "ross_mouth"
 $ lat      : num [1:4] -19.3 -19.3 -19.3 -19.2
 $ lon      : num [1:4] 147 147 147 147
 $ zone     : chr [1:4] "Upstream" "Middle" "Downstream" "Marine"
 - attr(*, "spec")=
  .. cols(
  ..   site_name = col_character(),
  ..   lat = col_double(),
  ..   lon = col_double(),
  ..   zone = col_character()
  .. )
 - attr(*, "problems")=<externalptr> 

Check sensor data (dates are in character format, legacy errors, and not

estuary_sonde_data
# A tibble: 11,520 × 5
   site       timestamp        temperature salinity turbidity
   <chr>      <chr>                  <dbl>    <dbl>     <dbl>
 1 upper_ross 01/05/2026 00:00        23.7     4.05      6.49
 2 mid_ross   01/05/2026 00:00        24.1    15.7      49.2 
 3 lower_ross 01/05/2026 00:00        24.2    28.9      48.1 
 4 ross_mouth 01/05/2026 00:00        24.6    33.9      49.8 
 5 upper_ross 01/05/2026 00:15        26.1     3.96     25.2 
 6 mid_ross   01/05/2026 00:15        24.6    12.1      34.8 
 7 lower_ross 01/05/2026 00:15        22.9    30.9      33.9 
 8 ross_mouth 01/05/2026 00:15        20.6    33.9      27.4 
 9 upper_ross 01/05/2026 00:30        24.9     4.32     13.0 
10 mid_ross   01/05/2026 00:30        24.3    17.4      31.9 
# ℹ 11,510 more rows
head(estuary_sonde_data)
# A tibble: 6 × 5
  site       timestamp        temperature salinity turbidity
  <chr>      <chr>                  <dbl>    <dbl>     <dbl>
1 upper_ross 01/05/2026 00:00        23.7     4.05      6.49
2 mid_ross   01/05/2026 00:00        24.1    15.7      49.2 
3 lower_ross 01/05/2026 00:00        24.2    28.9      48.1 
4 ross_mouth 01/05/2026 00:00        24.6    33.9      49.8 
5 upper_ross 01/05/2026 00:15        26.1     3.96     25.2 
6 mid_ross   01/05/2026 00:15        24.6    12.1      34.8 
glimpse(estuary_sonde_data)
Rows: 11,520
Columns: 5
$ site        <chr> "upper_ross", "mid_ross", "lower_ross", "ross_mouth", "upp…
$ timestamp   <chr> "01/05/2026 00:00", "01/05/2026 00:00", "01/05/2026 00:00"…
$ temperature <dbl> 23.71379, 24.13302, 24.23558, 24.64147, 26.06955, 24.62576…
$ salinity    <dbl> 4.054812, 15.742962, 28.934938, 33.891350, 3.962750, 12.05…
$ turbidity   <dbl> 6.489046, 49.216967, 48.135752, 49.811493, 25.184739, 34.8…
str(estuary_sonde_data)
spc_tbl_ [11,520 × 5] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ site       : chr [1:11520] "upper_ross" "mid_ross" "lower_ross" "ross_mouth" ...
 $ timestamp  : chr [1:11520] "01/05/2026 00:00" "01/05/2026 00:00" "01/05/2026 00:00" "01/05/2026 00:00" ...
 $ temperature: num [1:11520] 23.7 24.1 24.2 24.6 26.1 ...
 $ salinity   : num [1:11520] 4.05 15.74 28.93 33.89 3.96 ...
 $ turbidity  : num [1:11520] 6.49 49.22 48.14 49.81 25.18 ...
 - attr(*, "spec")=
  .. cols(
  ..   site = col_character(),
  ..   timestamp = col_character(),
  ..   temperature = col_double(),
  ..   salinity = col_double(),
  ..   turbidity = col_double()
  .. )
 - attr(*, "problems")=<externalptr> 

Check species dictionary

species_dictionary
# A tibble: 4 × 2
  common_name   scientific_name          
  <chr>         <chr>                    
1 barramundi    Lates calcarifer         
2 mangrove_jack Lutjanus argentimaculatus
3 bream         Acanthopagrus spp.       
4 flathead      Platycephalus spp.       
head(species_dictionary)
# A tibble: 4 × 2
  common_name   scientific_name          
  <chr>         <chr>                    
1 barramundi    Lates calcarifer         
2 mangrove_jack Lutjanus argentimaculatus
3 bream         Acanthopagrus spp.       
4 flathead      Platycephalus spp.       
glimpse(species_dictionary)
Rows: 4
Columns: 2
$ common_name     <chr> "barramundi", "mangrove_jack", "bream", "flathead"
$ scientific_name <chr> "Lates calcarifer", "Lutjanus argentimaculatus", "Acan…
str(species_dictionary)
spc_tbl_ [4 × 2] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ common_name    : chr [1:4] "barramundi" "mangrove_jack" "bream" "flathead"
 $ scientific_name: chr [1:4] "Lates calcarifer" "Lutjanus argentimaculatus" "Acanthopagrus spp." "Platycephalus spp."
 - attr(*, "spec")=
  .. cols(
  ..   common_name = col_character(),
  ..   scientific_name = col_character()
  .. )
 - attr(*, "problems")=<externalptr> 

Combine excel tabs on catch log into one data frame so all sheets load

catch1 <- read_excel(here::here("data/workshop_2/estuary_catch_log.xlsx"), sheet = 1)
catch2 <- read_excel("../data/workshop_2/estuary_catch_log.xlsx", sheet = 2)
catch3 <- read_excel("../data/workshop_2/estuary_catch_log.xlsx", sheet = 3)
catch4 <- read_excel("../data/workshop_2/estuary_catch_log.xlsx", sheet = 4)

catch_data <- bind_rows(catch1, catch2, catch3, catch4)
# Clean up the environment
rm(catch1, catch2, catch3, catch4) # Clean up the environment

# Glimpse data
catch_data
# A tibble: 427 × 4
   site       date                species       count
   <chr>      <dttm>              <chr>         <dbl>
 1 Lower_ross 2026-05-01 00:00:00 barramundi        6
 2 Lower_ross 2026-05-01 00:00:00 MANGROVE JACK     3
 3 Lower_ross 2026-05-01 00:00:00 bream             4
 4 Lower_ross 2026-05-01 00:00:00 flathead          2
 5 Lower_ross 2026-05-02 00:00:00 barramundi        1
 6 Lower_ross 2026-05-02 00:00:00 MANGROVE JACK     1
 7 Lower_ross 2026-05-02 00:00:00 bream             3
 8 Lower_ross 2026-05-02 00:00:00 flathead          3
 9 Lower_ross 2026-05-03 00:00:00 MANGROVE JACK     2
10 Lower_ross 2026-05-03 00:00:00 flathead          3
# ℹ 417 more rows
head(catch_data)
# A tibble: 6 × 4
  site       date                species       count
  <chr>      <dttm>              <chr>         <dbl>
1 Lower_ross 2026-05-01 00:00:00 barramundi        6
2 Lower_ross 2026-05-01 00:00:00 MANGROVE JACK     3
3 Lower_ross 2026-05-01 00:00:00 bream             4
4 Lower_ross 2026-05-01 00:00:00 flathead          2
5 Lower_ross 2026-05-02 00:00:00 barramundi        1
6 Lower_ross 2026-05-02 00:00:00 MANGROVE JACK     1
glimpse(catch_data)
Rows: 427
Columns: 4
$ site    <chr> "Lower_ross", "Lower_ross", "Lower_ross", "Lower_ross", "Lower…
$ date    <dttm> 2026-05-01, 2026-05-01, 2026-05-01, 2026-05-01, 2026-05-02, 2…
$ species <chr> "barramundi", "MANGROVE JACK", "bream", "flathead", "barramund…
$ count   <dbl> 6, 3, 4, 2, 1, 1, 3, 3, 2, 3, 1, 8, 4, 1, 1, 2, 1, 2, 4, 2, 2,…
str(catch_data)
tibble [427 × 4] (S3: tbl_df/tbl/data.frame)
 $ site   : chr [1:427] "Lower_ross" "Lower_ross" "Lower_ross" "Lower_ross" ...
 $ date   : POSIXct[1:427], format: "2026-05-01" "2026-05-01" ...
 $ species: chr [1:427] "barramundi" "MANGROVE JACK" "bream" "flathead" ...
 $ count  : num [1:427] 6 3 4 2 1 1 3 3 2 3 ...

Alternative method for loading files and combining sheets

file_path <- "../data/workshop_2/estuary_catch_log.xlsx"
catch_data2 <- excel_sheets(file_path) |>
  map_dfr(~read_excel(path = file_path, sheet = .x))


catch_data2
# A tibble: 427 × 4
   site       date                species       count
   <chr>      <dttm>              <chr>         <dbl>
 1 Lower_ross 2026-05-01 00:00:00 barramundi        6
 2 Lower_ross 2026-05-01 00:00:00 MANGROVE JACK     3
 3 Lower_ross 2026-05-01 00:00:00 bream             4
 4 Lower_ross 2026-05-01 00:00:00 flathead          2
 5 Lower_ross 2026-05-02 00:00:00 barramundi        1
 6 Lower_ross 2026-05-02 00:00:00 MANGROVE JACK     1
 7 Lower_ross 2026-05-02 00:00:00 bream             3
 8 Lower_ross 2026-05-02 00:00:00 flathead          3
 9 Lower_ross 2026-05-03 00:00:00 MANGROVE JACK     2
10 Lower_ross 2026-05-03 00:00:00 flathead          3
# ℹ 417 more rows
head(catch_data2)
# A tibble: 6 × 4
  site       date                species       count
  <chr>      <dttm>              <chr>         <dbl>
1 Lower_ross 2026-05-01 00:00:00 barramundi        6
2 Lower_ross 2026-05-01 00:00:00 MANGROVE JACK     3
3 Lower_ross 2026-05-01 00:00:00 bream             4
4 Lower_ross 2026-05-01 00:00:00 flathead          2
5 Lower_ross 2026-05-02 00:00:00 barramundi        1
6 Lower_ross 2026-05-02 00:00:00 MANGROVE JACK     1
glimpse(catch_data2)
Rows: 427
Columns: 4
$ site    <chr> "Lower_ross", "Lower_ross", "Lower_ross", "Lower_ross", "Lower…
$ date    <dttm> 2026-05-01, 2026-05-01, 2026-05-01, 2026-05-01, 2026-05-02, 2…
$ species <chr> "barramundi", "MANGROVE JACK", "bream", "flathead", "barramund…
$ count   <dbl> 6, 3, 4, 2, 1, 1, 3, 3, 2, 3, 1, 8, 4, 1, 1, 2, 1, 2, 4, 2, 2,…
str(catch_data2)
tibble [427 × 4] (S3: tbl_df/tbl/data.frame)
 $ site   : chr [1:427] "Lower_ross" "Lower_ross" "Lower_ross" "Lower_ross" ...
 $ date   : POSIXct[1:427], format: "2026-05-01" "2026-05-01" ...
 $ species: chr [1:427] "barramundi" "MANGROVE JACK" "bream" "flathead" ...
 $ count  : num [1:427] 6 3 4 2 1 1 3 3 2 3 ...

Check Species and Site Names (no scientific names & inconsistent syntax)

catch_data |> 
  distinct(site)
# A tibble: 4 × 1
  site      
  <chr>     
1 Lower_ross
2 Mid_Ross  
3 ROSS MOUTH
4 Upper Ross
catch_data |> 
  distinct(species)
# A tibble: 4 × 1
  species      
  <chr>        
1 barramundi   
2 MANGROVE JACK
3 bream        
4 flathead     

Data Cleaning

Standardize text with String

#Standardize species and site names on catch log
catch_log <- catch_data |>
  mutate(
    # 1. Convert everything to lowercase
    species = str_to_lower(species),
    # 2. Trim any leading or trailing whitespace (invisible spaces at the ends)
    species = str_trim(species),
    # 3. Replace any spaces with underscores
    species = str_replace_all(species, pattern = " ", replacement = "_")
  ) |>
mutate(
    # 1. Convert everything to lowercase
    site = str_to_lower(site),
    # 2. Trim any leading or trailing whitespace (invisible spaces at the ends)
    site = str_trim(site),
    # 3. Replace any spaces with underscores
    site = str_replace_all(site, pattern = " ", replacement = "_")
  )

print(catch_log)
# A tibble: 427 × 4
   site       date                species       count
   <chr>      <dttm>              <chr>         <dbl>
 1 lower_ross 2026-05-01 00:00:00 barramundi        6
 2 lower_ross 2026-05-01 00:00:00 mangrove_jack     3
 3 lower_ross 2026-05-01 00:00:00 bream             4
 4 lower_ross 2026-05-01 00:00:00 flathead          2
 5 lower_ross 2026-05-02 00:00:00 barramundi        1
 6 lower_ross 2026-05-02 00:00:00 mangrove_jack     1
 7 lower_ross 2026-05-02 00:00:00 bream             3
 8 lower_ross 2026-05-02 00:00:00 flathead          3
 9 lower_ross 2026-05-03 00:00:00 mangrove_jack     2
10 lower_ross 2026-05-03 00:00:00 flathead          3
# ℹ 417 more rows
# Standardize site names on metadata to join with site on catch log later 
estuary_metadata <- estuary_metadata |>
  mutate(
    # 1. Convert everything to lowercase and replace old column 
    site_name = str_to_lower(site_name),
    # 2. Trim any leading or trailing whitespace (invisible spaces at the ends)
    site_name = str_trim(site_name),
    # 3. Replace any spaces with underscores
    site_name = str_replace_all(site_name, pattern = " ", replacement = "_")
  )

print(estuary_metadata)
# A tibble: 4 × 4
  site_name    lat   lon zone      
  <chr>      <dbl> <dbl> <chr>     
1 upper_ross -19.3  147. Upstream  
2 mid_ross   -19.3  147. Middle    
3 lower_ross -19.3  147. Downstream
4 ross_mouth -19.2  147. Marine    

Add scientific names by merging

clean_catch_log <- catch_log |>
  left_join(species_dictionary, by = join_by(species == common_name))  #ensure variable on left is from dataset specified on line above

print(clean_catch_log)
# A tibble: 427 × 5
   site       date                species       count scientific_name          
   <chr>      <dttm>              <chr>         <dbl> <chr>                    
 1 lower_ross 2026-05-01 00:00:00 barramundi        6 Lates calcarifer         
 2 lower_ross 2026-05-01 00:00:00 mangrove_jack     3 Lutjanus argentimaculatus
 3 lower_ross 2026-05-01 00:00:00 bream             4 Acanthopagrus spp.       
 4 lower_ross 2026-05-01 00:00:00 flathead          2 Platycephalus spp.       
 5 lower_ross 2026-05-02 00:00:00 barramundi        1 Lates calcarifer         
 6 lower_ross 2026-05-02 00:00:00 mangrove_jack     1 Lutjanus argentimaculatus
 7 lower_ross 2026-05-02 00:00:00 bream             3 Acanthopagrus spp.       
 8 lower_ross 2026-05-02 00:00:00 flathead          3 Platycephalus spp.       
 9 lower_ross 2026-05-03 00:00:00 mangrove_jack     2 Lutjanus argentimaculatus
10 lower_ross 2026-05-03 00:00:00 flathead          3 Platycephalus spp.       
# ℹ 417 more rows

Format dates and NA values in Sonde Dataset

clean_sensor_data = estuary_sonde_data |>
  mutate( 
    # change timestamp to date_time format
    timestamp = dmy_hm(timestamp),
    # covert hardware error to NA values
    turbidity = na_if(turbidity, -999.0),
    # convert negative salinity values to NA
    salinity = ifelse(salinity < 0, NA, salinity)
    )

Put Data into Cohesive Format

Put sensor data in daily format

# Sensor data is logged every 15 minutes, but catch data is daily. Create a daily summary table that calculates the mean temperature and salinity for each site on each day. 

daily_sensor <- clean_sensor_data |>
  mutate(
    # Round each timestamp DOWN to midnight of that day
    date = floor_date(timestamp, unit = "day"),
    # Ensure it matches date format of catch log by converting timestamp 
    date = as_date(date)
  ) |>
  # Group by site and date to calculate for each  unique combination of the two
  group_by(site, date) |>
  # Calculate means and remove NA values
  summarise(
    mean_temp     = mean(temperature, na.rm = TRUE),
    mean_salinity = mean(salinity,    na.rm = TRUE),
    # Remove grouping so table displays normally
    .groups = "drop"
  )

daily_sensor
# A tibble: 120 × 4
   site       date       mean_temp mean_salinity
   <chr>      <date>         <dbl>         <dbl>
 1 lower_ross 2026-05-01      23.8          28.4
 2 lower_ross 2026-05-02      24.0          27.7
 3 lower_ross 2026-05-03      24.2          28.1
 4 lower_ross 2026-05-04      24.0          28.2
 5 lower_ross 2026-05-05      23.9          27.6
 6 lower_ross 2026-05-06      24.0          28.2
 7 lower_ross 2026-05-07      24.0          27.6
 8 lower_ross 2026-05-08      24.0          28.0
 9 lower_ross 2026-05-09      24.0          27.8
10 lower_ross 2026-05-10      23.9          28.1
# ℹ 110 more rows

Merge catch data, spatial metadata, and daily water quality summaries into a single master data frame.

# Merge clean_catch_log, estuary_metadata, and your daily_sensor into a single master data frame

final_catch_data <- clean_catch_log |>
  left_join(estuary_metadata, by = join_by(site == site_name)) |>
  left_join(daily_sensor, by = join_by(site, date))

final_catch_data
# A tibble: 427 × 10
   site      date                species count scientific_name   lat   lon zone 
   <chr>     <dttm>              <chr>   <dbl> <chr>           <dbl> <dbl> <chr>
 1 lower_ro… 2026-05-01 00:00:00 barram…     6 Lates calcarif… -19.3  147. Down…
 2 lower_ro… 2026-05-01 00:00:00 mangro…     3 Lutjanus argen… -19.3  147. Down…
 3 lower_ro… 2026-05-01 00:00:00 bream       4 Acanthopagrus … -19.3  147. Down…
 4 lower_ro… 2026-05-01 00:00:00 flathe…     2 Platycephalus … -19.3  147. Down…
 5 lower_ro… 2026-05-02 00:00:00 barram…     1 Lates calcarif… -19.3  147. Down…
 6 lower_ro… 2026-05-02 00:00:00 mangro…     1 Lutjanus argen… -19.3  147. Down…
 7 lower_ro… 2026-05-02 00:00:00 bream       3 Acanthopagrus … -19.3  147. Down…
 8 lower_ro… 2026-05-02 00:00:00 flathe…     3 Platycephalus … -19.3  147. Down…
 9 lower_ro… 2026-05-03 00:00:00 mangro…     2 Lutjanus argen… -19.3  147. Down…
10 lower_ro… 2026-05-03 00:00:00 flathe…     3 Platycephalus … -19.3  147. Down…
# ℹ 417 more rows
# ℹ 2 more variables: mean_temp <dbl>, mean_salinity <dbl>

Add rows for when no individuals of each species were caught to ensure that every species is represented at every site, on every sampling day.

final_catch_data |> 
  complete(
    nesting(site, date, 
           # lat, lon, 
            zone, mean_temp, mean_salinity),
    scientific_name
  ) |>
  mutate(
    # Convert the resulting NA counts to 0
    count = coalesce(count, 0)
  )
# A tibble: 480 × 10
   site       date                zone   mean_temp mean_salinity scientific_name
   <chr>      <dttm>              <chr>      <dbl>         <dbl> <chr>          
 1 lower_ross 2026-05-01 00:00:00 Downs…      23.8          28.4 Acanthopagrus …
 2 lower_ross 2026-05-01 00:00:00 Downs…      23.8          28.4 Lates calcarif…
 3 lower_ross 2026-05-01 00:00:00 Downs…      23.8          28.4 Lutjanus argen…
 4 lower_ross 2026-05-01 00:00:00 Downs…      23.8          28.4 Platycephalus …
 5 lower_ross 2026-05-02 00:00:00 Downs…      24.0          27.7 Acanthopagrus …
 6 lower_ross 2026-05-02 00:00:00 Downs…      24.0          27.7 Lates calcarif…
 7 lower_ross 2026-05-02 00:00:00 Downs…      24.0          27.7 Lutjanus argen…
 8 lower_ross 2026-05-02 00:00:00 Downs…      24.0          27.7 Platycephalus …
 9 lower_ross 2026-05-03 00:00:00 Downs…      24.2          28.1 Acanthopagrus …
10 lower_ross 2026-05-03 00:00:00 Downs…      24.2          28.1 Lates calcarif…
# ℹ 470 more rows
# ℹ 4 more variables: species <chr>, count <dbl>, lat <dbl>, lon <dbl>

Calculate Statistics and Plot

Calculate sE for salinity

sal_sum <- 
  final_catch_data |>
  mutate(zone = factor(zone, levels = c("Marine", "Downstream", "Middle", "Upstream"))) |>
  group_by(zone) |>
  summarise(
    se_salinity = sd(mean_salinity) / sqrt(n()),
    sd_salinity = sd(mean_salinity, na.rm = TRUE),
    median_salinity = median(mean_salinity, na.rm = TRUE),
    .groups = "drop"
  )

sal_sum
# A tibble: 4 × 4
  zone       se_salinity sd_salinity median_salinity
  <fct>            <dbl>       <dbl>           <dbl>
1 Marine          0.0101       0.104           34.0 
2 Downstream      0.0350       0.357           27.9 
3 Middle          0.0384       0.395           15.0 
4 Upstream        0.0181       0.190            4.99

Make point and error plot

sal_sum |> 
  ggplot(aes(x = zone, y = median_salinity)) +
  geom_point() +
  geom_errorbar(aes(ymin = median_salinity - sd_salinity, ymax = median_salinity + sd_salinity), width = 0.2) +
  theme_minimal() +
  # scientific figures usually don't have titles
  labs(#title = "Median Salinity by Zone with Standard Deviation Error Bars",
       x = "Zone",
       y = "Median Salinity (ppt)")

Calculate Fish Count SE

fish_stats <- final_catch_data |> 
 mutate(zone = factor(zone, levels = c("Marine", "Downstream", "Middle", "Upstream"))) |>
  group_by(zone, scientific_name) |>
  summarise(
    mean_catch = mean(count),
    se_catch = sd(count) / sqrt(n()),
    .groups = "drop"
  )

fish_stats
# A tibble: 16 × 4
   zone       scientific_name           mean_catch se_catch
   <fct>      <chr>                          <dbl>    <dbl>
 1 Marine     Acanthopagrus spp.              2.59    0.347
 2 Marine     Lates calcarifer                1.81    0.254
 3 Marine     Lutjanus argentimaculatus       1.88    0.193
 4 Marine     Platycephalus spp.              5.67    0.237
 5 Downstream Acanthopagrus spp.              2.5     0.255
 6 Downstream Lates calcarifer                2       0.262
 7 Downstream Lutjanus argentimaculatus       2.22    0.304
 8 Downstream Platycephalus spp.              2.17    0.165
 9 Middle     Acanthopagrus spp.              2.48    0.279
10 Middle     Lates calcarifer                2.36    0.231
11 Middle     Lutjanus argentimaculatus       2.27    0.171
12 Middle     Platycephalus spp.              2.36    0.251
13 Upstream   Acanthopagrus spp.              2.75    0.294
14 Upstream   Lates calcarifer                4.8     0.309
15 Upstream   Lutjanus argentimaculatus       2.11    0.195
16 Upstream   Platycephalus spp.              2.76    0.328

Plot daily abundance by zone for each species

fish_stats |> 
  ggplot(aes(x = zone, y = mean_catch, fill = zone)) +
  geom_point(position = "dodge", size = 2, pch = 23) +
  geom_errorbar(aes(ymin = mean_catch - se_catch, ymax = mean_catch + se_catch), 
                position = position_dodge(0.9), width = 0.2) +
   #add in points from master data
   #geom_point(data = final_catch_data, aes(x = zone, y = count), 
            # position = position_jitter(width = 0.2), alpha = 0.5, size = 1, inherit.aes = FALSE) +
  facet_wrap(~ scientific_name, scales = "fixed") +
  theme_bw() +
  theme(
    strip.text = element_text(face = "italic", size = 10, colour = "grey20"),
    
    #Add in legend
    #legend.position = "bottom" 
    legend.position = "none"
  ) +
  labs(
    # comment out titles for publication
    #title = "Predatory Fish Abundance across Estuarine Salinity Gradients",
    #subtitle = "Ross River Estuary System, May 2026",
    x = "Spatial Zone",
    y = "Abundance (per day)",
    fill = "Spatial Zone"
  )