library(sp)
library(ggplot2)
Create a diagram of tessellated hexagons the ranks hexagon tiles based on their distance from the centre.
Dummy data
set.seed(123)
df <- dplyr::tibble(
id = 1:40,
group = c(rep(1, 4), rep(2, 4), rep(3, 12), rep(4, 20)),
org = sample(c("A", "B", "C", "D"), 40, TRUE, c(0.5, 0.2, 0.2, 0.1))
)
df |>
dplyr::group_by(org) |>
dplyr::count()
Create a grid of hexagon
dx <- ceiling(sqrt(nrow(df)))
dy <- dx
## Helper functions
deg2rad <- function(deg) {(deg * pi) / (180)} # Function to convert degrees to radians
hex_side <- function(area) {(3^0.25)*sqrt(2*(area/9))} # Get the length of a side of hexagon for a given area
hex_area <- function(side) ((3*sqrt(3))/2*side) # Get the area of a hexagon given its side length
# Function to draw a hexagon
draw_hex <- function(area=hex_area(1), offset_x = 0, offset_y = 0, id=1, tessellate=F){
side_length <- hex_side(area)
A <- sin(deg2rad(30)) * side_length
B <- sin(deg2rad(60)) * side_length
C <- side_length
(x <- c(0, 0, B, 2*B, 2*B, B) + (offset_x*B*2) + ifelse(tessellate == T, B, 0))
(y <- c(A+C, A, 0, A, A+C, 2*C) + (offset_y*(A+C)))
sp::Polygons(list(sp::Polygon(coords = matrix(c(x,y),ncol=2),hole = F)),ID=id)
}
# Draw a grid of hexagon tiles
draw_hexTiles <- function(area, offset_x_start=0, offset_x_end=4, offset_y_start=0, offset_y_end =4){
grid <- expand.grid(offset_x_start:offset_x_end, offset_y_start:offset_y_end)
grid$tessellate <- grid[,2] %% 2 == 0
hexes <- sp::SpatialPolygons(lapply(1:nrow(grid), function(i){
draw_hex(area, offset_x = grid[i,1], offset_y = grid[i,2], id =i, tessellate = grid[i,3])
}))
names(grid) <- c("offset_x", "offset_y", "tessellate")
grid <- data.frame(id = 1:nrow(grid),grid)
sp::SpatialPolygonsDataFrame(hexes, grid)
}
cellsize <- 1
C <- hex_side(cellsize)
A <- sin(deg2rad(30)) * C
B <- sin(deg2rad(60)) * C
hexAcross <- dx
hexUp <- dy
offset_x_start <- 0
offset_y_start <- 0
offset_x_end <- offset_x_start + hexAcross
offset_y_end <- offset_y_start + hexUp
hex_grid <- draw_hexTiles(
cellsize, offset_x_start, offset_x_end,
offset_y_start, offset_y_end
)
plot(hex_grid)
length(hex_grid)
## [1] 64
Calculate the distance of each tile from the centre.
# Get the centre hex
grid_centre <- rgeos::gCentroid(hex_grid)
hex_grid_centre_id <- over(grid_centre, hex_grid)$id
hex_grid_centre <- hex_grid[hex_grid@data$id == hex_grid_centre_id ,]
# get centroids of hexes
hex_grid_centroids <- rgeos::gCentroid(hex_grid, byid = TRUE) |>
as.data.frame() |>
dplyr::rename(x1 = x, y1 = y)
hex_grid_centre_centroid <- rgeos::gCentroid(hex_grid_centre) |>
as.data.frame() |>
dplyr::rename(x2 = x, y2 = y)
# calculate distance between centre hex and other hexes
d <- function(x1,x2, y1, y2){
sqrt((x2-x1)^2 + (y2-y1)^2)
}
distance <- hex_grid_centroids |>
dplyr::bind_cols(hex_grid_centre_centroid) |>
dplyr::mutate(distance = d(x1, x2, y1, y2)) |>
dplyr::pull(distance)
hex_grid@data <- cbind(hex_grid@data, hex_grid_centroids)
hex_grid@data$distance_from_centre <- distance
hex_grid@data$rank <- rank(distance, ties.method = "first")
Rank the tiles based on distance from centre.
# Version 1
ggplot(fortify(hex_grid)) +
geom_polygon(aes(long, lat, group = id), fill = NA, colour = "black") +
geom_text(data = hex_grid@data, aes(label = rank, x = x1, y = y1))
## Regions defined for each Polygons
hex_grid@data <- hex_grid@data |>
dplyr::left_join(
df, by = c("rank" = "id")
)
# Version 2
hex_grid@data$rank2 <- rank(rgeos::gDistance(hex_grid, hex_grid_centre, byid = TRUE), ties.method = "first")
ggplot(fortify(hex_grid)) +
geom_polygon(aes(long, lat, group = id), fill = NA, colour = "black") +
geom_text(data = hex_grid@data, aes(label = rank2, x = x1, y = y1))
## Regions defined for each Polygons
Join the data in and plot
hex_grid2 <- hex_grid[!is.na(hex_grid@data$org),]
hex_grid2_gg <- fortify(hex_grid2) |>
dplyr::left_join(hex_grid2@data |>
dplyr::mutate(id = as.character(id)) |>
dplyr:::select(id, cohort = group, rank2, org))
## Regions defined for each Polygons
## Joining, by = "id"
ggplot(hex_grid2_gg) +
geom_polygon(aes(long, lat, group = id, fill = as.factor(cohort)), colour = "black") +
geom_text(data = hex_grid2@data, aes(label = rank, x = x1, y = y1))
I may be able to get a better grouping (i.e. in concentric circles) if I de-tesselate the grid calculate distance then tesselate again. This could be done with the offset_x and offset_y variables.
Disolve the shapes by cohort
cohort_1 <- rgeos::gUnaryUnion(hex_grid2[hex_grid2@data$group == 1,], )
cohort_2 <- rgeos::gUnaryUnion(hex_grid2[hex_grid2@data$group == 2,], )
cohort_3 <- rgeos::gUnaryUnion(hex_grid2[hex_grid2@data$group == 3,], )
cohort_4 <- rgeos::gUnaryUnion(hex_grid2[hex_grid2@data$group == 4,], )
ggplot(hex_grid2_gg) +
geom_polygon(aes(long, lat, group = id, fill = as.factor(org), alpha = 1/cohort), colour = "black") +
geom_text(data = hex_grid2@data, aes(label = rank, x = x1, y = y1)) +
geom_polygon(data = cohort_1, aes(long, lat, group=group),
colour = "black", size =1, fill = NA) +
geom_polygon(data = cohort_2, aes(long, lat, group=group),
colour = "black", size =1, fill = NA) +
geom_polygon(data = cohort_3, aes(long, lat, group=group),
colour = "black", size =1, fill = NA)
This looks at the offset variables
hex_grid3 <- hex_grid
hex_grid3@data <- hex_grid3@data |>
dplyr::select(id, offset_x, offset_y, tessellate)
hex_grid3@data$centre <- hex_grid3@data$id == hex_grid_centre_id
centre_coords <- hex_grid3@data |>
dplyr::filter(centre == TRUE) |>
dplyr::select(offset_x, offset_y)
hex_grid3@data$offset_x2 <- centre_coords$offset_x
hex_grid3@data$offset_y2 <- centre_coords$offset_y
hex_grid3@data <- cbind(
hex_grid3@data,
rgeos::gCentroid(hex_grid3, byid = TRUE) |>
as.data.frame()
)
hex_grid3@data <- hex_grid3@data |>
dplyr::mutate(x1 = ifelse(tessellate == TRUE, offset_x + 0.5 , offset_x),
y1 = offset_y) |>
dplyr::mutate(x2 = ifelse(centre == TRUE, x1, NA),
y2 = ifelse(centre == TRUE, y1, NA)) |>
tidyr::fill(c(x2,y2), .direction = "updown") |>
dplyr::mutate(distance = d(x1, x2, y1, y2)) |>
dplyr::mutate(rank = rank(distance, ties = "first"))
ggplot(hex_grid3) +
geom_polygon(aes(long, lat, group = group), fill = NA, colour = "black") +
geom_text(data = hex_grid3@data, aes(x, y, label = rank))
## Regions defined for each Polygons
hex_grid32 <- hex_grid3
hex_grid32@data <- hex_grid32@data |>
dplyr::left_join(
df, by = c("rank" = "id")
) |>
dplyr::rename(cohort = group)
hex_grid32 <- hex_grid32[!is.na(hex_grid32@data$cohort),]
hex_grid32f <- fortify(hex_grid32) |>
dplyr::left_join(hex_grid32@data |>
dplyr::mutate(id = as.character(id)) |>
dplyr:::select(id, cohort, rank, org))
## Regions defined for each Polygons
## Joining, by = "id"
ggplot(hex_grid32f) +
geom_polygon(aes(long, lat, group = group, fill = cohort), colour = "black") +
geom_text(data = hex_grid32@data, aes(x, y, label = rank))
cohort_groups <- (hex_grid32@data$cohort |> unique())[-1] |>
purrr::map_df(~{
x <- hex_grid32[hex_grid32@data$cohort == .x,]
rgeos::gUnaryUnion(x) |>
fortify() |>
dplyr::mutate(cohort = .x) |>
dplyr::mutate(group = paste0(cohort, ".", group))
})
ggplot(hex_grid32f) +
geom_polygon(aes(long, lat, group = group, fill = as.factor(cohort), alpha = cohort != 4),
colour = "grey") +
geom_text(data = hex_grid32@data, aes(x, y, label = rank, alpha = cohort != 4)) +
geom_polygon(data = cohort_groups,
aes(long, lat, group = group),
colour = "black", size = 1,
fill = NA) +
scale_fill_viridis_d() +
coord_cartesian() +
theme_void()
## Warning: Using alpha for a discrete variable is not advised.