Plot tilted map in R

The examples in your link look like the coordinates have been transformed via a shear and a scale matrix. You can easily apply this to the coordinates you get from the usual fortify/join data that ggplot requires.

Need a unique character ID value:

oregon.tract$id=as.character(1:nrow(oregon.tract))

Fortify on that ID and join attribute data:

ofort = fortify(oregon.tract,region="id")
ofort = left_join(ofort, oregon.tract@data, c("id"="id"))

Shear/scale matrix [[2,1],[0,1]] obtained by some trial and error:

sm = matrix(c(2,1.2,0,1),2,2)

Get transformed coordinates:

xy = as.matrix(ofort[,c("long","lat")]) %*% sm

Put as extra columns in fortified data:

ofort$x = xy[,1]; ofort$y = xy[,2]

Plot the "white" attribute as fill colours:

ggplot(ofort, aes(x=x, y=y, group=id, fill=white)) + geom_polygon() + coord_fixed()

Giving:

enter image description here


Extending on @Spacedman's answer, creating a stacked map like the one shown in the question becomes quite simple. You just need to add another map layer and displace its y axis: e.g. aes(x=x, y=y+5) :

ggplot(data= ofort) + 
  geom_polygon( aes(x=x, y=y, group=id), fill= "white", color="gray30") + # layer 1
  geom_polygon( aes(x=x, y=y+5, group=id, fill=white)) +                  # layer 2
  geom_polygon( aes(x=x, y=y+10, group=id, fill=pop2000-white)) +         # layer 3
  theme(axis.text=element_blank(), axis.ticks=element_blank()) +
  scale_fill_distiller(palette = "RdBu", name = "Population") +
  annotate("text", x = -197, y = 55, size=5, color="gray35", label = "Non-white") +
  annotate("text", x = -197, y = 50, size=5, color="gray35", label = "White") +
  annotate("text", x = -197, y = 45, size=5, color="gray35", label = "Census tracts") +
  coord_fixed()

enter image description here


Here's an approach using 'sf', also at https://gist.github.com/obrl-soil/ad588993511d7294143406585cdf8f62

library(sf)
nc <- st_read(system.file('shape/nc.shp', package = 'sf'))

sm <- matrix(c(2, 1.2, 0, 1), 2, 2)

nc_tilt <- nc
nc_tilt$geometry <- nc_tilt$geometry * sm
st_crs(nc_tilt) <- st_crs(nc)

# or,
# library(dplyr)
# nc_tilt <- mutate(nc, geometry = geometry * sm) %>% 
#   st_set_crs(st_crs(nc))

plot(nc_tilt[c('NAME', 'AREA', 'BIR74', 'SID74', 'NWBIR74')])

enter image description here

A ggplot approach is best accomplished with patchwork, so you don't get caught up in aes() issues (e.g. trying to apply a fill across different data types, scaling separately etc) and you don't have to screw with the geometry any further:

library(ggplot2)
library(patchwork)

plots <- lapply(c('NAME', 'AREA', 'BIR74', 'SID74', 'NWBIR74'), function(i) {
 p <- ggplot(nc_tilt) +
    geom_sf(aes_string(fill = i), show.legend = FALSE) +
    theme_void()
  
  if(is.numeric(nc_tilt[[i]])) {
    p <- p + scale_fill_viridis_c()
  }
  p
})

Reduce(`/`, plots)
# or, purrr::reduce(plots, `/`)

enter image description here