############################################################
# Supplementary Code 1
# Proximity-based social network analysis
#
# Description:
# This script constructs weighted social networks based on
# spatial proximity between horses. Edge weights represent
# the proportion of observations in which dyads were within
# 300 cm of one another.
#
# Networks are undirected and weighted. Strength centrality
# is calculated from association weights, whereas shortest-
# path metrics (betweenness and closeness) are computed
# using transformed edge costs (1 - association strength).
############################################################


# 1. LOAD DATA
d <- readRDS("C:/XXX ")

# 2. LOAD LIBRARIES
library(data.table)
library(dplyr)
library(igraph)
library(openxlsx)
library(tidygraph)
library(ggraph)
library(ggplot2)

# 3. DATA PREPARATION
d_clean <- d %>%
filter(!is.na(avg_distance)) %>%
filter(!is.na(Horse1), !is.na(Horse2))
setDT(d_clean)
# Define proximity events (≤ 300 cm)
d_clean[, proximity := as.numeric(avg_distance <= 300)]

# 4. DYAD-LEVEL ASSOCIATION INDICES

edges <- d_clean %>%
mutate(
HorseA = pmin(Horse1, Horse2),
HorseB = pmax(Horse1, Horse2)
) %>%
group_by(period, HorseA, HorseB) %>%
summarise(
association = mean(proximity, na.rm = TRUE),
n_obs = n(),
.groups = "drop")
setDT(edges)

# 5. FUNCTIONS
build_matrix <- function(dat) {
horses <- unique(c(dat$HorseA, dat$HorseB))
mat <- matrix(0,
nrow = length(horses),
ncol = length(horses),
dimnames = list(horses, horses))

for (i in seq_len(nrow(dat))) {
h1 <- dat$HorseA[i]
h2 <- dat$HorseB[i]
mat[h1, h2] <- dat$association[i]
mat[h2, h1] <- dat$association[i]}
return(mat)}

# Compute network metrics
compute_metrics <- function(mat) {
net <- graph_from_adjacency_matrix(
mat,mode = "undirected",weighted = TRUE,diag = FALSE)
w <- E(net)$weight
w_cost <- 1 - w
data.frame(
  Horse = V(net)$name,
  Strength = igraph::strength(net, weights = w),
  Betweenness = igraph::betweenness(net, weights = w_cost, normalized = TRUE),
  Closeness = igraph::closeness(net, weights = w_cost, normalized = TRUE)
)


# 6. NETWORK ANALYSIS BY PERIOD
results <- data.frame()
graphs <- list()

for (p in unique(edges$period)) {
dat <- edges %>%
filter(period == p)
if (nrow(dat) == 0) next
mat <- build_matrix(dat)
if (nrow(mat) < 2) next
net <- graph_from_adjacency_matrix(
mat, mode = "undirected", weighted = TRUE, diag = FALSE)

metrics <- compute_metrics(mat)
if (nrow(metrics) == 0) next
metrics$Period <- p
results <- rbind(results, metrics)
graphs[[p]] <- net}
summary_table <- results %>%
group_by(Period) %>%
summarise(
mean_strength = mean(Strength),
mean_betweenness = mean(Betweenness),
mean_closeness = mean(Closeness),
.groups = "drop")


overall_edges <- d_clean %>%
mutate(
HorseA = pmin(Horse1, Horse2),
HorseB = pmax(Horse1, Horse2)
) %>%
group_by(HorseA, HorseB) %>%
summarise(
association = mean(proximity, na.rm = TRUE),
n_obs = n(),
.groups = "drop")

overall_mat <- build_matrix(overall_edges)
overall_net <- graph_from_adjacency_matrix(
overall_mat,
mode = "undirected",
weighted = TRUE,
diag = FALSE)

overall_metrics <- compute_metrics(overall_mat)
overall_metrics$Period <- "Overall"
results <- rbind(results, overall_metrics)
graphs[["Overall"]] <- overall_net
overall_summary <- overall_metrics %>%
summarise(
Period = "Overall",
mean_strength = mean(Strength),
mean_betweenness = mean(Betweenness),
mean_closeness = mean(Closeness))

summary_table <- rbind(summary_table, overall_summary)

name_map <- c(x=X,y=Y)

set.seed(123)

for (p in names(graphs)) {
net <- graphs[[p]]

tg <- as_tbl_graph(net) %>%
mutate(label = name_map[name])
p_plot <- ggraph(tg, layout = "fr") +
geom_edge_link(
aes(width = weight),
colour = "grey50",
alpha = 0.7) +
geom_node_point(size = 8,fill = "lightblue",shape = 21,colour = "black") +
geom_node_text(aes(label = label),size = 3,colour = "black") +
scale_edge_width(range = c(0.3, 2)) +
theme_void() +
ggtitle(paste("Proximity network -", p))

ggsave(
filename = paste0("network_", p, ".png"),plot = p_plot, width = 6, height = 6, dpi = 300)
print(p_plot)}
