Using birdsong to index the local health of New Zealand nature
By Sam McClatchie on 30th September 2021
The natural soundscape of New Zealand is ringing with birdsong. Unfortunately this natural wonder is currently confined to pockets of the country that are protected from introduced predators. The New Zealand government Department of Conservation (DOC) and community groups have embarked on an ambitious plan, called Predator Free New Zealand 2050, to rid as much of the country as possible of introduced predators that destroy the natural bird life and silence the soundscape. Neighbourhood groups contribute by trapping or poison baiting rats, mice, mustelids, hedgehogs, and brushtail possums to remove them from gardens and natural areas. In many cases the counts are tallied and posted on public databases (see <http://trapdoor.omegatech.co.nz> for example). Trapping success is assessed by DOC and by conservation organisations. The abundance of birds is tracked by large scale citizen science initiatives like the New Zealand Bird Atlas and the New Zealand Garden Bird Survey. But for many neighbourhood groups there is no index of the success of their efforts, other than the rising body count from traps, and in many cases this is not recorded either. Further, it is difficult to quantify the success of poison baiting because carcasses cannot be easily counted.
One way to quantify trapping success is to monitor the soundscape for changes in the levels of birdsong. The Cacophony Project bird monitor combines software, a cell phone, and a microphone to monitor birdsong. The birdsong index can be used as a proxy for bird abundance near the monitor. Results to date are promising, with studies documenting the development of the device (Steer 2010), species identification of morepork owl calls (Hunt et al. 2019), and comparison of bird monitoring methods (Coutinho 2021). More current information is available on the Cacophony Project blog <https://www.2040.co.nz/blogs/news>.
The purpose of this article is to present new open source R code to analyse the birdsong recordings produced by the Cacophony bird monitor. The code loads and cleans the data, prepares them for plotting, and creates a useful panel of summary plots. These can be updated with new data from the Cacophony Project server, as they are uploaded from the bird monitor connected to the Internet via wireless. The plots derive a variety of useful metrics from the birdsong data. The level and variability of the dawn chorus as well as both day and night birdsong are summarised by weekly boxplots. The Cacophony Project automatic identification of Morepork owl (Ninox novaeseelandiae) calls has recently been improved (see <https://www.2040.co.nz/blogs/news/moreporks-automatically-identified>) and a weekly index is derived from the number of calls identified. You can see the effect of the improved identification in the Morepork owl graph after week 22. The diurnal time series is plotted from the entire dataset, and the full time series by date is shown and summarised by a smoothed regression. This new R code fills a gap between the Cacophony Project software that calculates the birdsong index and identifies the owl calls, and users who need a convenient summary of the data that can be rapidly and conveniently updated.
Code
Exporting the bird recording data yields a text file that is a little inconvenient to work with in R. The first cleanup step is to separate the cacophony index (the bird call index) string into separate variables:
### plot_cacophony_index.R
#####################################
library(tidyverse)
library(lubridate)
library(scales)
library(gridExtra)
#####################################
## load and clean data
# #####################################
# load raw data
rec <- read_csv("../data/recordings.csv")# make the string of cacophony index values into separate variables
tt <- str_replace_all(rec$`Cacophony Index`, ";", ",")write.table(tt, "../data/cacophony_index_only.csv", sep=",", col.names=FALSE, row.names=FALSE)
Then you can use the Linux routine ‘sed’ <http://www.gnu.org/software/sed/manual/sed.html> to conveniently remove quotes:
# remove the quotes with system command to sed
system("pwd")
system("ls -al")
system("sed 's/\"//g' ../data/cacophony_index_only.csv > ../data/edited_cacophony_index_only.csv")
system("mv ../data/edited_cacophony_index_only.csv ../data/cacophony_index_only.csv")# read the cleaned up data
rec2 <- read_csv("../data/cacophony_index_only.csv", col_names=c("index1","index2","index3"))
system("rm ../data/cacophony_index_only.csv")
The data need to be prepared for plotting:
#####################################
## prepare data for plotting
#####################################
# convert date and time to a time index
dt <- paste(rec$Date, rec$Time, sep=" ")
rec$date_time <- ymd_hms(dt, tz = "Pacific/Auckland")
# add the separated index variables to the data frame
rec3 <- cbind(rec, rec2)# calculate mean cacophony index
x <- c(rec3$index1,rec3$index2,rec3$index3)
rec3$index <- apply(rec2, 1, mean)
rec3$index
#subset index > 30 to remove artificially low values
rec3 <- with(rec3, rec3[index >=30, ])# subset dawn chorus data (between 4AM and 7AM)
dawn <- with(rec3, rec3[hour(Time) >=4 & hour(Time) <= 7, ])
dawn$month <- format(dawn$Date, "%m")
dawn$week <- format(dawn$Date, "%V")# subset day data (between 10AM and 4PM)
day <- with(rec3, rec3[hour(Time) >=10 & hour(Time) <= 15, ])
day$month <- format(day$Date, "%m")
day$week <- format(day$Date, "%V")
day$type <- rep("day", length(day$week))# subset night data when morepork occur (between midnight and 3AM)
night <- with(rec3, rec3[hour(Time) >=0 & hour(Time) <= 2, ])
night$month <- format(night$Date, "%m")
night$week <- format(night$Date, "%V")
night$type <- rep("night", length(night$week))# prepare morepork call index
rec3$species <- as.factor(rec3$"Species Classification")
rec3$morepork_calls <- str_count(rec3$species, pattern = "morepork")
rec3$morepork_calls <- rec3$morepork_calls/ 20 # 3 sec listen in each minute of recording
rec3$month <- format(rec3$Date, "%m")
rec3$week <- format(rec3$Date, "%V")
Now the plots are specified:
#####################################
## create plots
#####################################
# plot dawn chorus weekly boxplot time series
Dawn_Cacophony_Index_box <- ggplot(dawn, aes(x=week, y=index)) +
geom_boxplot(fill = "#95B9C7") +
xlab("Week of the year") +
ylab("Mean Cacophony Index") +
ggtitle("Dawn chorus 04-08h") +
theme(axis.text.x=element_text(angle=60, hjust=1)) +
theme(text = element_text(size=14)) +
ylim(25,85)
# plot day and night data weekly boxplot time series on same graph
rec3_type <- rbind(day, night)
Day_Night_Cacophony_Index_box <- ggplot(rec3_type, aes(x=week, y=index, fill = type)) +
geom_boxplot() +
scale_fill_manual(values = c("#82CAFF", "#0000A0")) +
guides(colour = "colorbar", size = "legend", shape = "legend") +
xlab("Week of the year") +
ylab("Mean Cacophony Index") +
ggtitle("Day 10-16h, Night 00-03h") +
theme(axis.text.x=element_text(angle=60, hjust=1)) +
theme(text = element_text(size=14)) +
ylim(25,85)
# plot morepork index weekly boxplot time series
Morepork_Index_box <- ggplot(rec3, aes(x = week, y = morepork_calls)) +
geom_boxplot(color = "#0000A0") +
xlab("Week of the year") +
ylab("Morepork Index (calls/ min)") +
ggtitle("Morepork owl calls") +
theme(axis.text.x=element_text(angle=60, hjust=1)) +
theme(text = element_text(size=14)) +
ylim(0,1.5)
# plot diurnal time series
Cacophony_Index_daily <- ggplot(rec3, aes(x=Time, y=index)) +
geom_point(color="orange", size=0.5) +
xlab("24 hour Time") +
ylab("Mean Cacophony Index") +
ggtitle("Diurnal period") +
theme(axis.text.x=element_text(angle=60, hjust=1)) +
theme(text = element_text(size=14))
Cacophony_Index_daily_trend <- Cacophony_Index_daily + stat_smooth(color = "red")
# plot entire time series
Cacophony_Index_full_ts <- ggplot(rec3, aes(x=date_time, y=index)) +
geom_point(color="orange", size=0.5) +
xlab("Date") +
ylab("Mean Cacophony Index") +
ggtitle("Full time series") +
theme(axis.text.x=element_text(angle=60, hjust=1)) +
theme(text = element_text(size=14))
Cacophony_Index_full_ts_trend <- Cacophony_Index_full_ts +
stat_smooth(color = "red")
CacIdx_full <- Cacophony_Index_full_ts_trend +
(scale_x_datetime(breaks=date_breaks("7 day")))
The final step is to create the panel from the plots:
# layout plots on the page
widths <- c(1,1,1,1,2)
grid.arrange(Dawn_Cacophony_Index_box, Day_Night_Cacophony_Index_box, Morepork_Index_box, Cacophony_Index_daily_trend, CacIdx_full, layout_matrix = rbind(c(1,2,3),c(4,5,5)))
The full R code is available here <http://u.pc.cd/f0nrtalK>. This is live code that will likely change, and perhaps improve with time.
Next steps
The next step is to obtain more bird monitors to conduct a properly controlled scientific study in trapped and control areas within the Huia (Waitakere Ranges) Trap.NZ footprint <https://trap.nz/project/1106292/info>. In the trapping group, we have two neighbours properties that have been intensively trapped for the last 3 years, and several other neighbours properties that are lightly trapped. With 6 bird monitors I could monitor two levels of high trap effort, two levels of low trap effort, and two control areas. Or four levels of high trap effort, and two control areas, which might be better, given the variability .Some of the fluctuations in bird song are undoubtedly due to variation in the weather, probably mainly temperature, wind and rain. To account for this variability, it will be necessary to install a weather station to monitor local conditions, so that weather variables can be statistically related to variability in the bird song index.
Conclusion
The Cacophony Project bird monitor provides an exciting new tool that should allow us to evaluate the effectiveness of neighbourhood trapping on local bird abundance in New Zealand. We present some new open source R code for plotting the data in an informative format. The code can conveniently display several useful indices as the data are collected and uploaded to the Cacophony server on the Internet. The expectation is that with time, perhaps over several years, it will be possible to detect an increase in bird song if the neighbourhood trapping and poison baiting is effectively reducing predator density. An interesting difference may be that Morepork owl calls could decrease if they are heavily reliant on rats and mice for food. Nature is full of surprises.
References
J. Steer, Bioacoustic monitoring of New Zealand birds (2010), Notornis 57, 75–80.
T.D. Hunt, M. Nikora and C. Blackbourn, Analysis of morepork vocalizations recorded using a permanently located mobile phone, (2019) Presented at the 32nd Annual Conference of the National Advisory Committee on Computing Qualifications, Nelson, NZ, Oct. 9–11.
S. Alves Coutinho, SCIE393 Report — WWW Document (2021), https://drive.google.com/file/d/1kskRUL_MJLG4Ldv1TFJXWSkO4dAQFOFh/view?usp=embed_facebook (accessed 6.23.21).