library(ggchord2)
library(ggplot2)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, unionSimple chord diagram
trade <- data.frame(
source = c("USA", "USA", "China", "China", "Germany", "Germany"),
target = c("China", "Germany", "USA", "Germany", "USA", "China"),
freq = c(50, 30, 60, 25, 35, 20)
)
ggplot(
data = trade,
mapping = aes(
source = source,
target = target,
freq = freq
)
) +
geom_chord_diagram()
Colour by source node:
ggplot(
data = trade,
mapping = aes(
source = source,
target = target,
freq = freq,
fill = source
)
) +
geom_chord_diagram()
Facet by year:
trade_ts <- rbind(
cbind(trade, year = 2022),
data.frame(
source = c("USA", "China", "Germany"),
target = c("China", "USA", "USA"),
freq = c(65, 70, 40),
year = 2023
)
)
ggplot(
data = trade_ts,
mapping = aes(
source = source,
target = target,
freq = freq,
fill = source
)
) +
geom_chord_diagram() +
facet_wrap(~year)
Asymmetric flows
flows <- data.frame(
source = c("Europe", "Europe", "Asia", "Asia", "Americas", "Americas"),
target = c("Asia", "Americas", "Europe", "Americas", "Europe", "Asia"),
freq = c(12, 8, 15, 6, 9, 5)
)
ggplot(
data = flows,
mapping = aes(
source = source,
target = target,
freq = freq,
fill = source
)
) +
geom_chord_diagram(
gap_degree = 3,
inner_radius = 0.55,
outer_radius = 0.72
)
Including flows from a source into itself:
flows <- data.frame(
source = c("Europe", "Europe", "Asia", "Asia"),
target = c("Europe", "Americas", "Europe", "Americas"),
freq = c(12, 8, 15, 17)
)
ggplot(
data = flows,
mapping = aes(
source = source,
target = target,
freq = freq,
fill = source
)
) +
geom_chord_diagram(
gap_degree = 3,
inner_radius = 0.55,
outer_radius = 0.72
)
Individual layers for more control
g <- ggplot(
data = trade,
mapping = aes(
source = source,
target = target,
freq = freq
)
) +
geom_chord_arcs(
mapping = aes(fill = source),
alpha = 0.5
) +
geom_chord_sectors(
mapping = aes(fill = source),
colour = "white",
linewidth = 0.8
) +
geom_chord_labels(
mapping = aes(colour = source),
size = 4
)
g
Add ggplot2 styling:
g +
scale_colour_brewer(palette = "Dark2") +
scale_fill_brewer(palette = "Dark2") +
coord_fixed() +
theme_void() +
theme(legend.position = "none")
If you have many segments, there may not be enough space for the labels.
set.seed(123)
n <- 15
flows <- expand.grid(
source = 1:n,
target = 1:n
) |>
filter(source < target) |>
mutate(
source = paste0("Category ", LETTERS[source]),
target = paste0("Category ", LETTERS[target]),
freq = rpois(((n^2 - n) / 2), 4)
)
g <- ggplot(
data = flows,
mapping = aes(
source = source,
target = target,
freq = freq
)
) +
geom_chord_arcs(
mapping = aes(fill = source),
alpha = 0.5
) +
geom_chord_sectors(
mapping = aes(fill = source),
colour = "white",
linewidth = 0.8
) +
coord_fixed() +
theme_void() +
theme(legend.position = "none")
g +
geom_chord_labels(
mapping = aes(colour = source),
size = 4
)
You can use perpendicular labels instead (you may need to adjust the x and y limits to fit all the labels in):
g +
geom_chord_labels_perp(
mapping = aes(colour = source),
size = 4
) +
scale_x_continuous(limits = c(-1.5, 1.5)) +
scale_y_continuous(limits = c(-1.5, 1.5))
Or just use curved labels:
g +
geom_chord_labels_curve(
mapping = aes(colour = source),
size = 4
) +
scale_x_continuous(limits = c(-1.5, 1.5))