Code
library(tidyverse) # ggplot, lubridate, dplyr, stringr, readr...
library(praise)library(tidyverse) # ggplot, lubridate, dplyr, stringr, readr...
library(praise)The datasets this week come from the paper “Sex Ratio Bias Triggers Demographic Suicide in a Dense Tortoise Population”. This topic seemed so interesting that even media like the New York Times picked it up: “Constant Sexual Aggression Drives Female Tortoises to Walk Off Cliffs”.
In an exceptionally dense island population of Hermann’s tortoises in Lake Prespa in North Macedonia, sexually coercive males dramatically overnumber females, inflict severe copulatory injuries and put them at risk of fatal falls from the island plateau’s sheer rock faces. Harassed females are emaciated, reproduce less frequently, produce smaller clutches and have lower annual survival rates compared to females from a neighbouring mainland population. Sixteen years of capture-recapture data reveal an ongoing extinction event and predict that the last island female will die in 2083.
Thank you to Novica Nakov, Free Software Macedonia for curating this week’s dataset.
clutch_size <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/main/data/2026/2026-03-03/clutch_size_cleaned.csv')
tortoise <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/main/data/2026/2026-03-03/tortoise_body_condition_cleaned.csv')clutch_size |>
ggplot() +
geom_point(aes(x = body_mass_grams, y = eggs, color = age)) +
facet_wrap((~locality))tortoise |>
group_by(individual) |>
summarize(count = n()) |>
arrange(desc(count))# A tibble: 2,139 × 2
individual count
<chr> <int>
1 644 27
2 138 20
3 465 20
4 877 20
5 446 19
6 800 19
7 335 18
8 462 18
9 893 18
10 898 18
# ℹ 2,129 more rows
tortoise |>
filter(individual == 644) |>
ggplot() +
geom_point(aes(x = year, y = straight_carapace_length_mm)) tortoise |>
group_by(individual) |>
summarize(count = n(), locality = first(locality), sex = first(sex))# A tibble: 2,139 × 4
individual count locality sex
<chr> <int> <chr> <chr>
1 1 12 Plateau m
2 10 4 Beach f
3 100 4 Plateau m
4 1000 1 Plateau m
5 1001 7 Plateau m
6 1003 2 Plateau m
7 1004 1 Plateau m
8 1005 12 Plateau m
9 1006 4 Plateau m
10 1007 8 Plateau m
# ℹ 2,129 more rows
tortoise |>
group_by(year, locality) |>
mutate(sex_ratio = mean(sex == "f")) |>
ggplot() +
geom_point(aes(x = sex_ratio, y = body_mass_grams, color = sex),
alpha = 0.5, size = 0.5) +
facet_wrap(~locality, scales = "free_x")tortoise |>
ggplot() +
geom_point(aes(x = body_mass_grams, y = body_condition_index, color = sex))tortoise |>
mutate(new_condition = body_mass_grams / straight_carapace_length_mm) |>
select(body_mass_grams, straight_carapace_length_mm, body_condition_index, new_condition)# A tibble: 10,174 × 4
body_mass_grams straight_carapace_length…¹ body_condition_index new_condition
<dbl> <dbl> <dbl> <dbl>
1 1230 183. 6.72 6.72
2 1271 184. 6.90 6.90
3 1239 186. 6.67 6.67
4 1205 187. 6.46 6.46
5 1300 182. 7.13 7.13
6 1269 186. 6.84 6.84
7 1302 185 7.04 7.04
8 1230 181 6.80 6.80
9 1305 184 7.09 7.09
10 1245 184 6.77 6.77
# ℹ 10,164 more rows
# ℹ abbreviated name: ¹straight_carapace_length_mm
We expect the body condition of females to be higher. Turns out that the female tortoises are only perceptibly larger in the mainland, Konjsko.
library(ggpattern)
tortoise |>
mutate(locality = forcats::fct_relevel(locality, c("Konjsko", "Beach", "Plateau")),
sex = ifelse(sex == "f", "F", "M")) |>
group_by(sex, locality) |>
mutate(ave_condition = mean(body_condition_index)) |>
ggplot() +
geom_violin_pattern(aes(y = body_condition_index, x = sex,
fill = locality, pattern = sex)) +
geom_boxplot(aes(y = body_condition_index, x = sex),
whisker.linewidth = 0, median.linewidth = 0,
width = .2, outliers = FALSE) +
geom_point(aes(y = ave_condition, x = sex),
shape = "+", size = 5) +
scale_pattern_manual(values = c("stripe", "none")) +
scale_fill_manual(values = c("#2F4F2F", "#6B8E23", "#A3B86C")) +
labs(pattern = "Sex", fill = "Locality", x = "", y = "Body condition") +
guides(fill = guide_legend(override.aes = list(pattern = "none"))) +
facet_grid(~ locality, switch = "x") +
theme_minimal()praise()[1] "You are transcendent!"