---
title: "Dance decoding method test"
author: "Abhinay Arra, Benjamin Rutschmann, Patrick L. Kohl"
date: "2025-01-21"
output:
  html_document: default
  pdf_document: default
---
**We used the following script to compare two methods of honeybee waggle dance decoding, the "waggle run method" and the "circuit method", with respect to their results regarding inferred foraging distances and directions. Our example is using dance data of Carnolian honeybees (*Apis mellifera carnica*) which are provided alongside our article published in *Apidologie* as a ".csv" file. To run this script, the data file should be placed in the same folder on your computer as this RMarkdown file. To use this script as is, rename the supplementary data file into "Dance_decoding_method_test_data.csv". The presented procedure can be applied to data sets of other bees in case one wishes to compare the two dance decoding methods in different populations or species of *Apis*:**

```{r setup, eval=FALSE}
library(here) #Load the "here" package to set the working directory to the folder where the Rmd file is located.
```

*Load the data:*
```{r}
dance_data <- read.csv("Dance_decoding_method_test_data.csv", sep = ";")
```

### 1. Comparison of foraging distances as inferred from the waggle method and the circuit method
#### 1A. Exploratory figures:

```{r}
library(ggplot2) #package for data visualization.
```

*Plot showing the overall relationship between the foraging distances inferred from dance circuits and waggle runs and a simple linear regression ("lm") fit:*
```{r}
ggplot(dance_data, aes(x = distance_waggle_km, y = distance_circuit_km)) + 
  geom_point(size = 1) + 
  labs(y = "Foraging distance (km) from dance circuits", x= "Foraging distance (km) from waggle runs") +  
  theme_classic()+
  geom_abline(intercept = 0, slope = 1, linetype = "dotted") +
  geom_smooth(method="lm")
```


*Plot highlighting potential differences in the fit among different random test colonies:*
```{r}
ggplot(dance_data, aes(x = distance_waggle_km, y = distance_circuit_km, colour=colony_ID)) + 
  geom_point(size = 1) + 
  labs(y = "Foraging distance (km) from dance circuits", x= "Foraging distance (km) from waggle runs") +  
  theme_classic()+
  geom_abline(intercept = 0, slope = 1, linetype = "dotted") +
  geom_smooth(method="lm")
```

#### 1B. Finding a suitable linear model to describe the relationship

We have data from four different bee colonies, which represent random samples (random because we could have used any other colonies).
Dances within a single colony are not independent: it is plausible that there are small dance dialect differences between colonies or that the colonies show sightly different relationship between the foraging distances from waggle duration and circuit duration because they differ in their nutritional states. Therefore, we first create a linear mixed effect model of the foraging distances from dance circuits as a function of the foraging distances from waggle runs with random slopes and intercepts of Colony ID (this is our full preferred model).

*Loading Required Packages:*
```{r message=FALSE, warning=FALSE}
library(lme4)# package for performing linear mixed models.
library(lmerTest)# package needed to produce p values in summaries of linear mixed models.
library(MuMIn) # package to calculate marginal R-squared (variation explained by fixed effects) and conditional R-squared (variation explained by both fixed and random effects).
```

*Model with random slopes and intercepts of Colony ID ("lmm"):*
```{r}
lmm <- lmer(distance_circuit_km ~ distance_waggle_km +(distance_waggle_km|colony_ID), data=dance_data)

```

The "lmm" should be our preferred model as it is consistent with the experimental design. However, in our case, "lmm" results into a "singular fit", i.e. the differences in slope and/or intercept between colonies are estimated to be exactly zero. Therefore, we build the next less complex model that only accounts for different intercepts between colonies ("lmm2"):
```{r}
lmm2 <- lmer(distance_circuit_km ~ distance_waggle_km +(1|colony_ID), data=dance_data)
summary(lmm2)
```

The model "lmm2" does not result in a "singular fit", so we choose this model for the further analysis.

*(Note: If "lmm2", as "lmm", resulted in a "singular fit", we would assume that there are no relevant differences between the test colonies. In that case, it would be reasonable to create a simple linear model, with the following formula:*

```{r}
lm <- lm(distance_circuit_km ~ distance_waggle_km, data=dance_data)

```
*)*

#### 1C. Formal test to check whether the relationship between foraging distances from dance circuits and waggle runs differs from the perfect fit (y=x)

The first step is to describe the chosen model ("lmm2") using the information on model coefficients from the summary function. We also calculate the marginal R-squared as a measure of goodness of fit:
```{r}
coef(summary(lmm2))

r.squaredGLMM(lmm2) # this produces the pseudo-R-squared values for linear mixed models
```

We have an intercept of 0.0856 (85.6m) that is significantly different from zero (p=0.0373), and a slope of 1.051, that is also significantly different from zero (p<0.0001). We have a marginal R-squared (R2m) of 0.7931 (we are only interested in the marginal R-squared, i.e. in the variation explained by the fixed effect only).

The significant intercept means that the foraging distances inferred from dance circuits significantly overestimate the foraging distance inferred from waggle runs by approx. 86m. It is not surprising that the slope of the original model is different from zero because we knew beforehand that waggle run duration and circuit duration are correlated. We rather want to know whether the slope significantly deviates from one. To test this, we create a linear model of the *difference between the foraging distances inferred from dance circuits and waggle runs* as a function of the foraging distances inferred from waggle runs. We could also say that we perform a regression on the residuals. We take the same type of model that we chose in the previous step (random intercept only):

```{r}
lmm2_residuals <- lmer(distance_circuit_km-distance_waggle_km ~ distance_waggle_km +(1|colony_ID), data=dance_data)
summary(lmm2_residuals)
```
The summary again tells us that the intercept is at 85.6 m with the same p-value as before. The estimate for the factor distance_waggle_km is 0.051, which is logical as it is the slope of the original model (1.051) minus one.
Based on the p-value of 0.1953 we decide by convention (p>0.05) that the slope is not significantly different from zero. 
This, in turn, means that the slope in the original model is not different from one.

The conclusions we can draw from this analysis is that foraging distances inferred from circuit duration overestimate foraging distances inferred from waggle runs by about 86 m (intercept differs from zero) regardless of which foraging distance class is considered (slope not different from one). Since we assume that the distances inferred from waggle runs are accurate, distances inferred using the circuit method can be "corrected" by subtracting 86 m.

#### 1D. Visualization of the final model "lmm2":

*Creating a data frame for the predicted values:*
```{r}
mellifera_prediction <- data.frame(distance_waggle_km=seq(min(dance_data$distance_waggle_km), 
                                                       max(dance_data$distance_waggle_km), 
                                                       length.out=100))
# Get predictions with confidence intervals
predicted_values <- predict(lmm2, newdata = mellifera_prediction, re.form = NA, se.fit = TRUE)

# Add predictions and confidence intervals to the prediction data frame
mellifera_prediction$distance_circuit_km <- predicted_values$fit
mellifera_prediction$upper <- predicted_values$fit + 1.96 * predicted_values$se.fit  # 95% CI upper bound
mellifera_prediction$lower <- predicted_values$fit - 1.96 * predicted_values$se.fit  # 95% CI lower bound
```

*Drawing a line based on the predicted data in a plot:*
```{r}
ggplot(dance_data, aes(x = distance_waggle_km, y = distance_circuit_km)) + 
  geom_point(shape=21, alpha=0.5, size= 1) + 
  labs(y = "Foraging distance (km) from dance circuits", x= "Foraging distance (km) from waggle runs") +  
  scale_x_continuous(breaks= seq(0,4, by=1), expand=c(0,0))+
  scale_y_continuous(breaks= seq(1,4, by=1),expand=c(0,0))+
  geom_abline(intercept = 0, slope = 1, linetype = "dotted") +
  geom_ribbon(data = mellifera_prediction, aes(ymin = lower, ymax = upper), 
              fill = "grey", alpha = 0.3) +  # Add ribbon for confidence interval
  geom_line(data = mellifera_prediction, aes(y = distance_circuit_km), 
            lwd = 0.7, lineend = "round", colour = "blue")+
  coord_fixed(xlim = c(0,4), ylim = c(0,4)) +
  theme_bw()
```

### 2. Correlation analysis of dance angles obtained from the circuit method and the waggle run method

*Loading package for circular statistics:*
```{r message=FALSE, warning=FALSE}
library(circular)
```

*The angle information needs to be transformed into class "circular" for the functions to work:*
```{r message=FALSE, warning=FALSE}
dance_data$dance_angle_circular <- as.circular(dance_data$dance_angle_circuits, units="degrees")
dance_data$mean_angle_waggles_circular <- as.circular(dance_data$mean_angle_waggles, units="degrees")
```

*Performing a circular correlation test:*
```{r}
cor.circular(x=dance_data$dance_angle_circular, y=dance_data$mean_angle_waggles_circular, test=TRUE)
```
The correlation coefficient (cor) can be interpreted like Pearson's correlation coefficient r for linear data. Here, cor is 0.982, so there is a very high correlation between the dance angles obtained from both methods. The p-value (p.value) is very low or close to zero, meaning the correlation is highly significant.

We can conclude that the angles obtained from both methods are not different.

*Visualization of the dance angles obtained from circuit method and waggle run method:*
```{r}
ggplot(dance_data, aes(x = mean_angle_waggles, y = dance_angle_circuits_corrected_for_plotting)) +
  geom_point(shape=21, alpha=0.5, size= 1) +
  labs(y = "Mean angle (°) from circuit method", x= "Mean angle (°) from waggle run method ") + 
  scale_x_continuous(breaks= seq(0,360, by=90), expand=c(0,0))+
  scale_y_continuous(breaks= seq(0,360, by=90),expand=c(0,0))+
  coord_fixed(xlim = c(-15,375), ylim = c(-15,375)) +
  geom_abline(intercept = 0, slope = 1, linetype="dotted") +
  theme_bw()
```


