Twelve people from my family and my Navy service, in three circles: my immediate family, the in-laws who joined it through marriage, and two Navy best friends. My husband and I met in the Navy, so the circles overlap rather than sitting side by side.
nodes <- tribble(
~name, ~circle, ~birth_month,
"Me", "Me", "January",
"Husband", "Family", "April",
"Sis 1", "Family", "September",
"Sis 2", "Family", "July",
"Brother", "Family", "May",
"SIL (bro)", "In-law", "February",
"SIL (hus)", "In-law", "October",
"SIL (class)", "In-law", "January",
"BIL 1", "In-law", "May",
"BIL 2", "In-law", "June",
"Best friend 1","Navy", "February",
"Best friend 2","Navy", "December"
)
SIL (bro) is my brother’s wife, SIL (hus) my husband’s sister, SIL (class) my high school classmate who later became Sis 2’s sister-in-law, BIL 1 Sis 1’s husband, and BIL 2 Sis 2’s husband.
The connections follow four patterns: my core family all know each other; the in-laws who married into my side know that whole core family; the Navy group includes my husband, my brother, and both best friends, who have also met Sis 1, my husband’s sister, and my brother’s wife; and two ties cross circles, since SIL (class) was my classmate before she was family and also knows Sis 1 through a shared interest in BTS.
edges <- tribble(
~from, ~to,
# Core family
"Me", "Husband", "Me", "Sis 1", "Me", "Sis 2", "Me", "Brother",
"Husband", "Sis 1", "Husband", "Sis 2", "Husband", "Brother",
"Sis 1", "Sis 2", "Sis 1", "Brother", "Sis 2", "Brother",
# In-laws who married into my side
"BIL 1", "Me", "BIL 1", "Husband", "BIL 1", "Sis 1",
"BIL 1", "Sis 2", "BIL 1", "Brother",
"BIL 2", "Me", "BIL 2", "Husband", "BIL 2", "Sis 1",
"BIL 2", "Sis 2", "BIL 2", "Brother",
"SIL (bro)", "Me", "SIL (bro)", "Husband", "SIL (bro)", "Sis 1",
"SIL (bro)", "Sis 2", "SIL (bro)", "Brother",
# My husband's sister
"SIL (hus)", "Husband", "SIL (hus)", "Me",
"SIL (hus)", "Sis 1", "SIL (hus)", "Brother",
# My classmate, now Sis 2's sister-in-law
"SIL (class)", "Me", "SIL (class)", "Sis 2", "SIL (class)", "BIL 2",
"SIL (class)", "Husband", "SIL (class)", "Sis 1",
# Navy
"Best friend 1", "Best friend 2",
"Best friend 1", "Me", "Best friend 1", "Husband",
"Best friend 1", "Sis 1", "Best friend 1", "Brother",
"Best friend 1", "SIL (hus)", "Best friend 1", "SIL (bro)",
"Best friend 2", "Me", "Best friend 2", "Husband",
"Best friend 2", "Sis 1", "Best friend 2", "Brother",
"Best friend 2", "SIL (hus)", "Best friend 2", "SIL (bro)"
)
my_net <- graph_from_data_frame(d = edges, vertices = nodes, directed = FALSE)
A <- as_adjacency_matrix(my_net, sparse = FALSE)
my_net
## IGRAPH 1e270b2 UN-- 12 47 --
## + attr: name (v/c), circle (v/c), birth_month (v/c)
## + edges from 1e270b2 (vertex names):
## [1] Me --Husband Me --Sis 1 Me --Sis 2 Me --Brother
## [5] Husband--Sis 1 Husband--Sis 2 Husband--Brother Sis 1 --Sis 2
## [9] Sis 1 --Brother Sis 2 --Brother Me --BIL 1 Husband--BIL 1
## [13] Sis 1 --BIL 1 Sis 2 --BIL 1 Brother--BIL 1 Me --BIL 2
## [17] Husband--BIL 2 Sis 1 --BIL 2 Sis 2 --BIL 2 Brother--BIL 2
## [21] Me --SIL (bro) Husband--SIL (bro) Sis 1 --SIL (bro) Sis 2 --SIL (bro)
## [25] Brother--SIL (bro) Husband--SIL (hus) Me --SIL (hus) Sis 1 --SIL (hus)
## [29] Brother--SIL (hus)
## + ... omitted several edges
pal <- c(Me = "#E76F51", Family = "#2A9D8F",
`In-law` = "#E9C46A", Navy = "pink")
V(my_net)$color <- pal[V(my_net)$circle]
set.seed(123)
plot(my_net,
layout = layout_with_fr(my_net),
vertex.size = 10 + degree(my_net) * 2,
vertex.label.color = "black",
vertex.label.cex = 0.8,
vertex.frame.color = "white",
edge.color = "grey70",
main = "My family and Navy network")
legend("bottomleft", legend = names(pal), pt.bg = pal, pch = 21,
pt.cex = 1.6, bty = "n", cex = 0.85)
Degree counts direct connections, betweenness measures how often someone bridges two others, PageRank rewards being connected to well-connected people, and triangles counts the closed three-person groups someone belongs to.
tibble(
person = V(my_net)$name,
circle = V(my_net)$circle,
degree = degree(my_net),
betweenness = round(betweenness(my_net), 2),
pagerank = round(page_rank(my_net)$vector, 4),
triangles = count_triangles(my_net)
) %>%
arrange(desc(degree)) %>%
kable(caption = "Centrality and triangle counts") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| person | circle | degree | betweenness | pagerank | triangles |
|---|---|---|---|---|---|
| Me | Me | 11 | 4.62 | 0.1133 | 36 |
| Husband | Family | 11 | 4.62 | 0.1133 | 36 |
| Sis 1 | Family | 11 | 4.62 | 0.1133 | 36 |
| Brother | Family | 10 | 2.92 | 0.1035 | 32 |
| Sis 2 | Family | 8 | 1.30 | 0.0854 | 22 |
| SIL (bro) | In-law | 7 | 0.40 | 0.0749 | 19 |
| Best friend 1 | Navy | 7 | 0.17 | 0.0751 | 20 |
| Best friend 2 | Navy | 7 | 0.17 | 0.0751 | 20 |
| SIL (hus) | In-law | 6 | 0.00 | 0.0658 | 15 |
| BIL 2 | In-law | 6 | 0.20 | 0.0664 | 14 |
| SIL (class) | In-law | 5 | 0.00 | 0.0572 | 10 |
| BIL 1 | In-law | 5 | 0.00 | 0.0566 | 10 |
tibble(
measure = c("People", "Relationships", "Density", "Diameter",
"Average path length"),
value = c(vcount(my_net), ecount(my_net),
round(edge_density(my_net), 3),
diameter(my_net), round(mean_distance(my_net), 3))
) %>%
kable(caption = "Whole-network summary") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| measure | value |
|---|---|
| People | 12.000 |
| Relationships | 47.000 |
| Density | 0.712 |
| Diameter | 2.000 |
| Average path length | 1.288 |
Pairs who share a mutual connection but don’t know each other directly — the logic behind “People You May Know.”
shared <- A %*% A
candidates <- which(upper.tri(shared) & shared > 0 & A == 0, arr.ind = TRUE)
tibble(
person_a = rownames(A)[candidates[, "row"]],
person_b = colnames(A)[candidates[, "col"]],
mutual_friends = shared[candidates]
) %>%
arrange(desc(mutual_friends)) %>%
kable(caption = "Unconnected pairs with mutual connections") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
| person_a | person_b | mutual_friends |
|---|---|---|
| SIL (bro) | SIL (hus) | 6 |
| Brother | SIL (class) | 5 |
| SIL (bro) | BIL 1 | 5 |
| SIL (bro) | BIL 2 | 5 |
| BIL 1 | BIL 2 | 5 |
| Sis 2 | Best friend 1 | 5 |
| Sis 2 | Best friend 2 | 5 |
| Sis 2 | SIL (hus) | 4 |
| SIL (bro) | SIL (class) | 4 |
| SIL (hus) | BIL 1 | 4 |
| SIL (class) | BIL 1 | 4 |
| SIL (hus) | BIL 2 | 4 |
| BIL 1 | Best friend 1 | 4 |
| BIL 2 | Best friend 1 | 4 |
| BIL 1 | Best friend 2 | 4 |
| BIL 2 | Best friend 2 | 4 |
| SIL (hus) | SIL (class) | 3 |
| SIL (class) | Best friend 1 | 3 |
| SIL (class) | Best friend 2 | 3 |
My husband and I are each connected to everyone else in the network. That happened because we met in the Navy alongside my best friends and then married into each other’s families, so his relatives and my service friends met directly instead of through one of us relaying between them.
The result is a network with no bridge person. Density is high, the diameter is small, and betweenness is low for everyone, so any two people here reach each other in a step or two. That is the opposite of the tutorial’s example network, where one person sits on nearly every path.
Degree still separates people whose formal family roles look identical. Sis 1 and Sis 2 have the same standing in the family, but Sis 1 has met both best friends and my husband’s sister and Sis 2 has not, so Sis 1 sits noticeably better connected. Relationship category and network position are not the same thing.
What the analysis didn’t surface is just as telling. Every birth-month match is between people who already know each other, and the friend-of-friend list is short. Both techniques need sparse networks to produce anything useful, and mine is dense. The main limitation is that the network is undirected and unweighted, so a sibling I speak to daily counts the same as an in-law I see once a year; adding edge weights for contact frequency would be the most useful next step.