Created
May 22, 2023 16:39
-
-
Save marcosci/57430ec059f9cc91bb5da6c5d13539bd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# load libraries | |
library(units) | |
library(tidyverse) | |
library(osmdata) | |
library(sf) | |
library(ggtext) | |
library(exactextractr) | |
library(fasterize) | |
library(ggtext) | |
library(tidygeocoder) | |
library(glue) | |
library(purrr) | |
library(geosphere) | |
library(classInt) | |
library(patchwork) | |
library(glue) | |
sf::sf_use_s2(TRUE) | |
#epsg <- 32632 | |
epsg <- 4326 | |
country <- 'germany' | |
aoi_citys <- c('Berlin, Germany', | |
'Hamburg, Germany', | |
'München, Germany', | |
'Köln, Germany', | |
'Frankfurt, Germany', | |
'Stuttgart, Germany', | |
'Kiel, Germany', | |
'Leipzig, Germany', | |
'Dortmund, Germany') | |
figureground <- map_dfr(aoi_citys, function(aoi_city){ | |
city <- tidygeocoder::geo(aoi_city) %>% | |
st_as_sf(coords = c("long", "lat"), crs = 4326) %>% | |
st_transform(epsg) | |
buildings <- getbb(aoi_city)%>% | |
opq(timeout = 100)%>% | |
add_osm_feature(key = "building", | |
value = c("apartments", | |
"detached", | |
"dormitory", | |
"farm", | |
"hotel", | |
"house", | |
"residential", | |
"semidetached_house" | |
)) %>% | |
osmdata_sf() | |
buildings_sf <- buildings$osm_polygons %>% | |
st_transform(epsg) | |
crop_buffer <- st_buffer(city, 7500) | |
buildings_sf <- st_crop(buildings_sf, crop_buffer) | |
buildings_sf <- st_intersection(buildings_sf, crop_buffer) | |
buildings_area <- as.numeric(sum(st_area(buildings_sf))) | |
buffer_area <- as.numeric(sum(st_area(crop_buffer))) - buildings_area | |
total_area <- as.numeric(sum(st_area(crop_buffer))) | |
df <- tibble(x = c(1, 2), | |
type = c("Void", "Solid"), | |
city = rep(factor(aoi_city), 2), | |
count = c(buffer_area, buildings_area)) |> | |
mutate(count = as.numeric(count)) | |
circleFun <- function(center=c(0,0), diameter=1, npoints=500, start=0, end=2, type, aoi, coverage_figure = NA, coverage_ground = NA) | |
{ | |
tt <- seq(start*pi, end*pi, length.out=npoints) | |
data.frame(x = center[1] + diameter / 2 * cos(tt), | |
y = center[2] + diameter / 2 * sin(tt), | |
type = type, | |
aoi = aoi, | |
coverage_figure = coverage_figure, | |
coverage_ground = coverage_ground) | |
} | |
half_circles_solid <- circleFun(c(0,7.625), | |
sqrt(buildings_area), | |
start=0.5, | |
end=1.5, | |
type = "Solid", | |
aoi = aoi_city, | |
coverage_figure = round(buildings_area / total_area * 100, 2)) | |
half_circles_void <- circleFun(c(0,7.625), | |
sqrt(buffer_area), | |
start=1.5, | |
end=2.5, | |
type = "Void", | |
aoi = aoi_city, | |
coverage_ground = round(buffer_area / total_area * 100, 2)) | |
rbind(half_circles_solid, | |
half_circles_void) | |
}) | |
figureground |> | |
arrange(aoi) |> | |
ggplot() + | |
geom_polygon(aes(x,y, fill = type)) + | |
scale_fill_manual(values = c("#ad9a8c", "#f1eeeb")) + | |
facet_wrap(vars(aoi)) + | |
scale_x_continuous(expand = expansion(mult = c(0.1, .1))) + | |
# annotate("richtext", | |
# x = -4000, | |
# y = 250, | |
# label.color = NA, | |
# fill = NA, | |
# hjust = 0.5, | |
# label = glue("<span style='text-align: center;'><b style = 'font-size:16pt; font-weight: 100;'>{coverage_ground} %</b> <br> Solid</span>")) + | |
# annotate("richtext", | |
# x = 8000, | |
# y = 250, | |
# label.color = NA, | |
# fill = NA, | |
# hjust = 0.5, | |
# label = glue("<span style='text-align: center;'><b style = 'font-size:16pt; font-weight: 100;'>{coverage_figure} %</b> <br> Void</span>")) + | |
coord_equal() + | |
theme_void() + | |
theme(legend.position = "none", | |
panel.spacing.y = unit(1, "lines"), | |
#plot.margin = margin(2, 2, 2, 2, "cm"), | |
strip.text.x = element_text(size = 9, face = "bold"), | |
text = element_text(family="West")) | |
wrapper <- function(label, dev_width = dev.size("in")[1], dev_scaler = 18) { | |
paste(strwrap(label, dev_width * dev_scaler), collapse = "\n") | |
} | |
figureground |> | |
arrange(aoi) |> | |
ggplot() + | |
geom_polygon(aes(x,y, fill = type)) + | |
scale_fill_manual(values = c("#ad9a8c", "#f1eeeb")) + | |
facet_wrap(vars(aoi)) + | |
scale_x_continuous(expand = expansion(mult = c(0.1, .1))) + | |
guides(fill = guide_legend(keyheight = unit(1, units = "mm"), | |
keywidth = unit(5, units = "mm"), | |
direction = "horizontal", | |
nrow = 1, | |
ticks.colour = "white", | |
label.position = "bottom", | |
title.position = "bottom", | |
title.hjust = 0.5)) + | |
coord_equal() + | |
theme_void() + | |
labs(title = "Figure Ground", | |
subtitle = "The figure-ground diagram serves as a mapping technique that showcases the \n correlation between developed and undeveloped areas within urban environments. \n This method visually represents the land occupied by buildings as a solid mass or 'figure', \n while the open spaces, including streets, parks, and plazas, are depicted as voids or ground. \n Here, we look at the 9 biggest German cities.", | |
caption = "Data: OSM | Visualisation: Marco Sciaini", | |
fill='') + | |
theme(legend.direction="horizontal", | |
legend.position="bottom", | |
legend.box = "vertical", | |
panel.spacing.y = unit(1, "lines"), | |
plot.title = element_text(size = 18, | |
colour = '#171717', | |
hjust = 0.5, | |
margin = margin(.3,0,.5,-2, "cm")), | |
plot.subtitle = element_text(size = 9, | |
colour = '#171717', | |
hjust = 0.5, | |
margin = margin(.3,0,.5,-2, "cm"), | |
lineheight = 1.3), | |
plot.caption = element_text(size = 6, | |
colour = '#171717', | |
margin = margin(.3,-2,.3,0, "cm")), | |
strip.text.x = element_text(size = 7, face = "bold"), | |
text = element_text(family="West")) | |
ggsave("single.png", width = 9, height = 16, dpi = 600) | |
figureground_sf <- map(aoi_citys, function(aoi_city){ | |
city <- tidygeocoder::geo(aoi_city) %>% | |
st_as_sf(coords = c("long", "lat"), crs = 4326) %>% | |
st_transform(epsg) | |
buildings <- getbb(aoi_city)%>% | |
opq(timeout = 100)%>% | |
add_osm_feature(key = "building", | |
value = c("apartments", | |
"detached", | |
"dormitory", | |
"farm", | |
"hotel", | |
"house", | |
"residential", | |
"semidetached_house" | |
)) %>% | |
osmdata_sf() | |
buildings_sf <- buildings$osm_polygons %>% | |
st_transform(epsg) | |
crop_buffer <- st_buffer(city, 7500) | |
buildings_sf <- st_crop(buildings_sf, crop_buffer) | |
buildings_sf <- st_intersection(buildings_sf, crop_buffer) | |
list(buildings_sf, crop_buffer) | |
}) | |
street_plot <- ggplot() + | |
geom_sf(data = figureground_sf[[1]][[2]], color = "#f1eeeb", fill = "#f1eeeb", lwd = .25, alpha = 0.8) + | |
geom_sf(data = figureground_sf[[1]][[1]], color = "#ad9a8c", lwd = .15, alpha = 0.6) + | |
theme_void() | |
street_plot | |
n_buildings <- nrow(figureground_sf[[1]][[1]]) | |
coverage_figure <- figureground |> | |
filter(aoi == "Berlin, Germany") |> | |
pull(coverage_figure) |> | |
unique() |> | |
na.omit() | |
coverage_ground <- figureground |> | |
filter(aoi == "Berlin, Germany") |> | |
pull(coverage_ground) |> | |
unique() |> | |
na.omit() | |
circle_plot <- figureground |> | |
filter(aoi == "Berlin, Germany") |> | |
ggplot() + | |
geom_polygon(aes(x,y, fill = type)) + | |
scale_fill_manual(values = c("#ad9a8c", "#f1eeeb")) + | |
scale_x_continuous(expand = expansion(mult = c(0.14, .14))) + | |
guides(fill = guide_legend(keyheight = unit(1, units = "mm"), | |
keywidth = unit(5, units = "mm"), | |
direction = "horizontal", | |
nrow = 1, | |
ticks.colour = "white", | |
label.position = "bottom", | |
title.position = "bottom", | |
title.hjust = 0.5)) + | |
coord_equal() + | |
theme_void() + | |
labs(#title = glue("{aoi_citys[1]} | {n_buildings} Buildings"), | |
caption = "Data: OSM | Visualisation: Marco Sciaini", | |
fill='') + | |
annotate("richtext", | |
x = -3000, | |
y = 250, | |
label.color = NA, | |
fill = NA, | |
hjust = 0.5, | |
label = glue("<span style='text-align: center;'><b style = 'font-size:16pt; font-weight: 100;'>{coverage_figure} %</b> <br> Solid</span>")) + | |
annotate("richtext", | |
x = 7200, | |
y = 250, | |
label.color = NA, | |
fill = NA, | |
hjust = 0.5, | |
label = glue("<span style='text-align: center;'><b style = 'font-size:16pt; font-weight: 100;'>{coverage_ground} %</b> <br> Void</span>")) + | |
theme(legend.direction="horizontal", | |
legend.position="bottom", | |
legend.box = "vertical", | |
panel.spacing.y = unit(1, "lines"), | |
plot.title = element_text(size = 18, | |
colour = '#171717', | |
hjust = 0.5, | |
margin = margin(.3,0,.5,-2, "cm")), | |
plot.subtitle = element_text(size = 9, | |
colour = '#171717', | |
hjust = 0.5, | |
margin = margin(.3,0,.5,-2, "cm"), | |
lineheight = 1.3), | |
plot.caption = element_text(size = 12, | |
colour = '#171717', | |
margin = margin(.3,-2,.3,0, "cm")), | |
strip.text.x = element_text(size = 7, face = "bold"), | |
text = element_text(family="West")) | |
street_plot + circle_plot + plot_annotation( | |
title = glue("{aoi_citys[1]} | {n_buildings} Buildings"), | |
theme = theme( plot.title = element_text(size = 18, | |
face = "bold", | |
colour = '#171717', | |
hjust = 0.5, | |
margin = margin(.3,0,.5,-2, "cm"))) | |
) | |
ggsave("both.png", width = 16, height = 9, dpi = 600) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment