library(FSA)
# Preview standard length categories for our four species
psdVal("Bluegill")
psdVal("Largemouth Bass")
psdVal("Walleye")
psdVal("Channel Catfish")Size structure
PSD
PSD stands for “Proportional Stock Density”. It essentially means the proportion of fish of stock size that are of quality size or greater. This is a common metric used in fisheries management to assess the health of a fish stock and to make informed decisions about fishing regulations and conservation efforts.
To calculate PSD, you would typically use the following formula: \[ PSD = \left( \frac{\text{Number of fish} \geq \text{quality size}}{\text{Number of fish} \geq \text{stock size}} \right) \times 100 \]
The length at which a fish is considered to be of “quality size” can vary depending on the species, and we use Gabelhouse lengths. Gabelhouse lengths, developed in 1984, are standardized, minimum total lengths (in mm or inches) used to categorize fish populations into stock, quality, preferred, memorable, and trophy sizes for assessing fish population structure. These categories provide precise, universal metrics for measuring fisheries
Generally, Gabelhouse length categories are as follows: - Stock Length: The minimum length at which fish are considered part of the population. 20-26% of trophy size - Quality Length: The minimum length at which fish are considered of good eating quality. 26-40% of trophy size - Preferred Length: The minimum length at which fish are considered to be of preferred size for anglers. 40-60% of trophy size - Memorable Length: The minimum length at which fish are considered to be of memorable size for anglers. 60-80% of trophy size - Trophy Length: The minimum length at which fish are considered to be of trophy size for anglers. 80% or more of the maximum size
The PSD metric is important for fisheries management because it helps to determine the size structure of the fish population. A high PSD indicates that a large proportion of the fish are of quality size or greater, which can be a sign of a healthy fish stock. Conversely, a low PSD may indicate that the fish population is dominated by smaller, less desirable fish, which can be a sign of overfishing or poor habitat conditions.
We can also estimate an RSD if we want to know the proportion of fish that are of memorable size or larger. For RSD we use the following formula:
\[ RSD\text{-}X = \left( \frac{\text{Number of fish} \geq \text{size category X}}{\text{Number of fish} \geq \text{stock size}} \right) \times 100 \]
In a healthy population, what do you think is the proportion of stock, quality, preferred, memorable, and trophy fish? Is it better to use PSD or to do a histogram of size distribution to understand the size structure of a population? Why?
Remember, these metrics use standardized length categories defined for each species (Stock, Quality, Preferred, Memorable, Trophy). Consult psdVal() in the FSA package.
The Data
For this assignment you will work with electrofishing survey data collected from a reservoir in the Midwest. Four species were sampled: Bluegill, Largemouth Bass, Walleye, and Channel Catfish. Total lengths (mm) were recorded for each individual.
Load the electrofishing.csv file from Canvas and read into R in an object called fish_data. Then, use head() to look at the first few rows of the data.
In a few words, describe the dataset.
Part 1 – Calculating PSD and RSD by Hand
Before using FSA functions, it is important to understand what those functions are computing. In this section you will calculate PSD and RSD manually for each species.
Step-by-step workflow (example: Bluegill)
Use psdVal() to look up the standard length thresholds, then use logical subsetting to count fish in each category.
Before you run this code!
Remember how we created a file with only one of the species (e.g., Monarchs) when we worked with the butterfly data? You will need to do the same thing here for each species.
You can use the same code as before, or also filter() from the dplyr package to create a new data frame for each species. For example, for Bluegill:
library(dplyr)
bluegill <- fish_data %>% filter(species == "Bluegill")This is easier that the other way, but does requires a package (dplyr). You can also do
bluegill <- fish_data[fish_data$species == "Bluegill", ]Which follows the logic of R more closely, but is a bit more cumbersome.
# Step 1: retrieve the breakpoints
bg_breaks <- psdVal("Bluegill")
bg_breaks # Stock, Quality, Preferred, Memorable, Trophy substock stock quality preferred memorable trophy
0 80 150 200 250 300
# Step 2: filter to stock size and above
bg_stock <- bluegill %>% filter(tl_mm >= bg_breaks["stock"])# Step 3: count fish >= quality
bg_quality <- bluegill %>% filter(tl_mm >= bg_breaks["quality"])# Step 4: calculate PSD
PSD_bluegill <- (nrow(bg_quality) / nrow(bg_stock)) * 100
round(PSD_bluegill, 1)[1] 38.2
✏️ Your Turn
Using the workflow above, complete the following for all four species.
For each species, calculate:
- PSD (quality and above / stock and above)
- RSD-P (preferred and above / stock and above)
- RSD-M (memorable and above / stock and above) — where applicable
Fill in the table like the one below with your results (you can introduce tables in your qmd):
| Species | N (stock+) | PSD | RSD-P | RSD-M |
|---|---|---|---|---|
| Bluegill | ||||
| Largemouth Bass | ||||
| Walleye | ||||
| Channel Catfish |
Complete the part 1 section
Part 2 – Calculating PSD and RSD with FSA
The FSA package provides psdCalc(), which automates the computations above and adds 95% confidence intervals using the binomial method.
Syntax
psdCalc(~tl_mm, data = your_data, species = "Species Name", what = "all")~tl_mm— formula referencing the length column
species— must match an entry inpsdVal()exactly
what = "all"— returns PSD and all RSD values
Example – Bluegill
psdCalc(~tl_mm, data = bluegill, species = "Bluegill", what = "all") Estimate 95% LCI 95% UCI
PSD-Q 38 32 44
PSD-P 12 8 15
PSD S-Q 62 56 68
PSD Q-P 27 21 32
PSD P-M 12 8 15
Estimate PSD and RSD values for all four species using psdCalc(). Do the results match your manual calculations? If not, can you explain why?
Visualizing Size Structure
Visualizing the length-frequency distribution helps us understand where fish are concentrated across size categories and how the population is structured.
Histograms
A length-frequency histogram is one of the most common tools in fisheries science. We will add vertical lines for each PSD breakpoint to provide biological context.
Example – Bluegill
bg_breaks <- psdVal("Bluegill")
ggplot(data=bluegill,aes(x = tl_mm)) +
geom_histogram(binwidth = 15, fill = "steelblue", color = "white", alpha = 0.85) +
geom_vline(xintercept = bg_breaks[c("stock", "quality", "preferred", "memorable")],
linetype = "dashed", color = "firebrick", linewidth = 0.7) +
annotate("text",
x = bg_breaks[c("stock", "quality", "preferred", "memorable")] + 4,
y = Inf,
label = c("S", "Q", "P", "M"),
vjust = 1.5, hjust = 0, color = "firebrick", fontface = "bold") +
labs(title = "Bluegill Length-Frequency",
x = "Total Length (mm)", y = "Count") +
theme_classic()Plot the histogram for all species. You can base your code on the one I provided for Bluegill, but make sure to adjust the breakpoints and labels for each species. Describe the size structure of each population based on your histograms.
Looking at the community
We can plot all size distributions using a density plot:
# Retrieve stock-size cutoffs for each species and filter accordingly
fish_data_stock <- fish_data %>%
group_by(species) %>%
ungroup()
ggplot(fish_data_stock, aes(x = tl_mm, fill = species, color = species)) +
geom_density(alpha = 0.25, linewidth = 0.8) +
labs(title = "Size Structure Density – All Four Species (Stock Size and Above)",
x = "Total Length (mm)",
y = "Density",
fill = "Species",
color = "Species") +
theme_classic() +
theme(legend.position = "bottom")Based on the density plot, are any of the species dominated by small fish or large fish?
Tic-Tac-Toe Plot
(Bluegill & Largemouth Bass)
The tic-tac-toe plot is a great way to use the PSD data. It visualizes whether the proportion of quality fish for a prey and predator species is the way we want it.
Essentially, you, as a manager choose some target PSD values for your two species, in this case Bluegill and Largemouth Bass.
The target PSD values depends on whether we want a pond with an abundance of panfish, one with balanced populations, or one with larger bass.
The following table shows the target PSD values for each of those scenarios:
| Scenario | Bluegill PSD | Largemouth PSD |
|---|---|---|
| Panfish abundant | 50-80 | 20-40 |
| Balanced | 20-60 | 40-70 |
| Big Bass | 10-50 | 50-80 |
We can then use the ticTacToe() function from the FSA package to visualize where our PSD values fall in relation to those targets.
We can plot the tic-tac-toe section for the “Panfish” scenario as follows:
tictactoe(predlab="Largemouth Bass", preylab="Bluegill PSD", predobj=c(20,40),preyobj=c(50,80))When we want a pond dominated by Panfish, we want a lot of large bluegill, and not too many Largemouth Bass. So, we want our bluegill PSD to be high (50-80), and our bass PSD to be low (20-40). Essentially, we want our PSD values to fall right on the shaded area of the tic-tac-toe plot. If our PSD values fall outside of that area, then we are not meeting the target for that scenario. But! You can tell why
We can add our observed PSD values like this:
First, we need the values we observed:
psdCalc(~tl_mm, data = bluegill, species = "Bluegill", what = "all") Estimate 95% LCI 95% UCI
PSD-Q 38 32 44
PSD-P 12 8 15
PSD S-Q 62 56 68
PSD Q-P 27 21 32
PSD P-M 12 8 15
And we can see that the PSD for bluegill is 38, with a CI spanning from 32 to 44.
psdCalc(~tl_mm, data = bass, species = "Largemouth Bass", what = "all")Warning: Some category sample size <20, some CI coverage may be
lower than 95%.
Estimate 95% LCI 95% UCI
PSD-Q 42 35 50
PSD-P 15 10 21
PSD-M 2 0 4
PSD S-Q 58 50 65
PSD Q-P 27 20 34
PSD P-M 14 8 19
PSD M-T 2 0 4
And we can see that the PSD for Largemouth Bass is 42, with a CI spanning from 35 to 50.
library(plotrix)
tictactoe(predlab="Largemouth Bass", preylab="Bluegill PSD", predobj=c(20,40),preyobj=c(50,80))
plotCI(38, 42, li=32, ui=44, err="x",pch=16,add=TRUE)
plotCI(38, 42, li=35, ui=50, err="y",pch=16,add=TRUE)We are simply adding points and CI’s on top of the plot
If you are a manager that wants to create a pond dominated by panfish, do you think the current PSD values for Bluegill and Largemouth Bass are good? Why or why not? What do you need to do to meet the target PSD values for that scenario?
Plot a tic-tac-toe plot for the “Balanced” scenario. Add your observed PSD values for Bluegill and Largemouth Bass. Do you think the current PSD values are good for a balanced pond? Why or why not? What do you need to do to meet the target PSD values for that scenario?