Home > front end >  Create a Space Adjacency Matrix in ggplot
Create a Space Adjacency Matrix in ggplot

Time:04-12

I wish to create a Space Adjacency Matrix in R, preferably using ggplot/tidyverse for consistency with other scripts, but I am open to other solutions.

Here is what I am looking for.

A Space Adjacency Matrix is used in interior and architectural design to illustrate relationships (adjacencies) between spaces within a building.

Each space in the building has a relationship (or lack of relationship) to every other space.

The input data is likely formatted similarly to this:

rel.ABCD <- data.frame(
  id = c(1,2,3,4,5,6),
  x1 = c("A","A","A","B","B","C"),
  x2 = c("B","C","D","C","D","D"),
  relation = c(1,2,1,3,2,1)
)

rel.ABCD
#>   id x1 x2 relation
#> 1  1  A  B        1
#> 2  2  A  C        2
#> 3  3  A  D        1
#> 4  4  B  C        3
#> 5  5  B  D        2
#> 6  6  C  D        1

Created on 2022-04-11 by the sample space adjacency matrix from vectorworks

The relation is displayed at the intersecting grid for each room pair (e.g. dispatch and office have a relationship type 5, storage and shop have a relationship type 1, etc.). The relation is typically depicted as an icon, number or fill colour.

How can I generate this graph?

CodePudding user response:

I don't know of any package that implements this. But it is good to keep in mind that you can basically plot anything in ggplot2, as long as you can translate what you're plotting to polygons. That said, here is how you can translate this particular problem to polygons.

library(ggplot2)
#> Warning: package 'ggplot2' was built under R version 4.1.3

rel.ABCD <- data.frame(
  id = c(1,2,3,4,5,6),
  x1 = c("A","A","A","B","B","C"),
  x2 = c("B","C","D","C","D","D"),
  relation = c(1,2,1,3,2,1)
)

# Encode categorical values as numeric
union <- with(rel.ABCD, union(x1, x2))
rel.ABCD <- transform(
  rel.ABCD,
  x = match(x1, union),
  y = match(x2, union)
)

# Expand observation to rectangle polygons
new <- rel.ABCD[rep(seq_len(nrow(rel.ABCD)), each = 4),]
xpand <- c(-1, -1, 1, 1) * 0.5
ypand <- c(-1, 1, 1, -1) * 0.5
new <- transform(
  new,
  x = x   xpand,
  y = y   ypand
)

# Rotate coordinates 45 degrees
rotmat <- matrix(c(-0.5, 0.5, 0.5, 0.5), ncol = 2)
new[, c("x", "y")] <- t(rotmat %*% t(as.matrix(new[, c("x", "y")])))

# Plot
ggplot(new, aes(x, y, group = id))  
  geom_polygon(aes(fill = factor(relation)))  
  scale_y_continuous(breaks = seq_along(union),
                     labels = union)  
  coord_equal()

If you want the labels more like your example, you can also coerce these to polygons.

# Make dataframe for labels
labels <- data.frame(
  label = union,
  x = 0, y = seq_along(union)
)

# Write offset for label polygons
size <- 1
xoffset <- c(-size, -size, 0, 0.5, 0)
yoffset <- c(-0.5, 0.5, 0.5, 0, -0.5)

# Expand every label to a polygon
labels <- labels[rep(seq_len(nrow(labels)), each = 5), ]
labels <- transform(
  labels,
  x = x   xoffset,
  y = y   yoffset
)

ggplot(new, aes(x, y))  
  geom_polygon(aes(fill = factor(relation), group = id), 
               colour = "black")  
  geom_polygon(data = labels, aes(group = label), 
               colour = "black", fill = NA)  
  annotate(
    "text", 
    x = 0, y = seq_along(union), label = union,
    hjust = 1
  )  
  coord_equal()  
  guides(x = "none", y = "none")

Created on 2022-04-11 by the reprex package (v2.0.1)

  • Related