Visualize Fish Encounter Histories in R ggplot2

In this work, we’ll create a scatterplot of fish icons to illustrate the detection of tagged fish which swims upstream to downstream. This visualization is inspired from the work of Practical Pisces.


What Is a Fish Encounter History?

When working with tagged fish swimming in a river, we often generate a record of each fish’s “encounters” with the autonomous monitors in an underwater array. Encounter histories are the translation of a fish’s path into a row of ones (detected) and zeros (or NAs, not detected).

Packages and Data Preparation

The fish_encounters dataset is built in tidyr package, and already arranged in a tidy format. The station variable is a factor arranged from the most upstream (the “Release” station) to the most downstream.

library(dplyr)library(tidyr)library(ggplot2)
fish_encounters

Output:

# A tibble: 114 × 3
fish station seen
<fct> <fct> <int>
1 4842 Release 1
2 4842 I80_1 1
3 4842 Lisbon 1
4 4842 Rstr 1
5 4842 Base_TD 1
# ℹ 109 more rows

To get a better view of the dataset structure, we can transform the tidy dataset into a wider format with pivot_wider(): each row represents a different tagged fish, and each column represents a different monitor location (“Station”), and NA values represent a lack of detection of the fish at the related station.

fish_encounters %>%   pivot_wider(names_from = station, values_from = seen)

Output:

# A tibble: 19 × 12
fish Release I80_1 Lisbon Rstr Base_TD BCE BCW BCE2 BCW2 MAE MAW
<fct> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
1 4842 1 1 1 1 1 1 1 1 1 1 1
2 4843 1 1 1 1 1 1 1 1 1 1 1
3 4844 1 1 1 1 1 1 1 1 1 1 1
4 4845 1 1 1 1 1 NA NA NA NA NA NA
5 4847 1 1 1 NA NA NA NA NA NA NA NA
# ℹ 14 more rows

Visualization

Draw dots to illustrate the detention of each fish at each station. geom_path() is used to connect the dots in order of their appearance in the dataset by order of stations from upstream to downstream (though geom_line() here produces the same graphic effect). aes(group = fish) ensures that dots are connected respectively for each fish.

p1 <- fish_encounters %>%   ggplot(aes(x = station, y = fish, color = station)) +  geom_point() +  geom_path(aes(group = fish), size = 0.25, color = "black") 
p1

A typical pattern of encounter histories for outmigrating juvenile fish is to see the detection rate decline as they migrate downstream and succumb to predation or other mortality factors.

Draw fish icon. You can install the “Le Fish” font (available for download here) on your computer, and then register it with R via the extrafonts package. Once you have the font installed and registered, you can call it onto your plot with geom_text(). Fish shapes are encoded as alphabetical letters (not case sensitive).

library(extrafont)
p2 <- p1 + # create bigger fish icon: serves as a black outline geom_text(label = "X", size = 10, vjust = 0.6, family = "LEFISH", color = "black") + # create smaller fish icon: serve as inner fill geom_text(label = "X", size = 9, vjust = 0.6, family = "LEFISH") + # remove the color legend theme(legend.position = "none")
p2

You can check different fish shapes by the following code snippet.

expand.grid(x = 1:7, y = 5:1) %>% # create a position index grid  slice_head(n = 26) %>% # select the top 26 rows  mutate(z = LETTERS) %>% # fish alphabetical letters    ggplot(aes(x, y, label = z)) +   geom_text(size = 9, vjust = 0.6, family = "LEFISH") +  # draw fish icon  geom_text(aes(label = z, y = y + .4), size = 5) + # mark the associated letter  theme_void() 

Finally polish up the plot.

p3 <- p2 +      labs(title = "Encounter histories of tagged Chinook salmon smolts",       subtitle = "Upstream to downstream") +  scale_color_brewer(palette = "Spectral") +  hrbrthemes::theme_ipsum(base_size = 12) +  theme(legend.position = "none")
p3
library(dplyr)library(tidyr)library(ggplot2)
fish_encounters
# View the dataset structure as wider format.
fish_encounters %>% pivot_wider(names_from = station, values_from = seen)
### Visualization
# Draw dots to illustrate the detention of each fish at each station.p1 <- fish_encounters %>% ggplot(aes(x = station, y = fish, color = station)) + geom_point() + geom_path(aes(group = fish), size = 0.25, color = "black")
p1

# Draw fish icon. See "Stepwise instructions" tab to download the icon library. library(extrafont)p2 <- p1 + # create bigger fish icon: serves as a black outline geom_text(label = "X", size = 10, vjust = 0.6, family = "LEFISH", color = "black") + # create smaller fish icon: serve as inner fill geom_text(label = "X", size = 9, vjust = 0.6, family = "LEFISH") + # remove the color legend theme(legend.position = "none")
p2
# Finally polish up the plot. p3 <- p2 + labs(title = "Encounter histories of tagged Chinook salmon smolts", subtitle = "Upstream to downstream") + scale_color_brewer(palette = "Spectral") + hrbrthemes::theme_ipsum(base_size = 12) + theme(legend.position = "none")
p3
# You can check different fish shapes by the following code snippet. expand.grid(x = 1:7, y = 5:1) %>% # create a position index grid slice_head(n = 26) %>% # select the top 26 rows mutate(z = LETTERS) %>% # fish alphabetical letters ggplot(aes(x, y, label = z)) + geom_text(size = 9, vjust = 0.6, family = "LEFISH") + # draw fish icon geom_text(aes(label = z, y = y + .4), size = 5) + # mark the associated letter theme_void()