library(sf)
<- read_sf('v0_1-SVN.gpkg') dat_full
Building footprint area packing
Load the data
Read in the data from the EUBUCCO website (this takes a relatively long time):
This dataset is > 1 mil rows, for the purposes of this visualization, I’m only taking 1,000 randomly sampled rows
<- dat_full[sample(nrow(dat_full), 1000), ] dat
Calculate area of each polygon
Each row in the ‘geom’ column contains a polygon. We can use an sf package function to calculate the area of each polygon and save it in a separate column. For plotting, we’ll assume each polygon is a square (which it isn’t), and save the sides of the square as well.
library(dplyr)
library(knitr)
Warning: package 'knitr' was built under R version 4.2.3
$area <- st_area(dat$geom)
dat
<- dat |>
dat mutate(side_x = sqrt(area), side_y = sqrt(area)) |>
st_drop_geometry() |>
# save only coordinates to pass on to python
select(side_x, side_y)
$side_x <- as.numeric(dat$side_x)
dat$side_y <- as.numeric(dat$side_y)
dat
kable(head(dat))
side_x | side_y |
---|---|
13.71021 | 13.71021 |
12.76360 | 12.76360 |
13.88291 | 13.88291 |
14.80616 | 14.80616 |
14.04543 | 14.04543 |
34.19548 | 34.19548 |
Rectangle packing
Now, we pass these data to python & use the rpack
library to derive coordinates to pack rectangles into a plot:
= r.dat
dat_py # round to nearest integer, otherwise the rpack function doesn't work
= round(dat_py, 0).astype(int)
dat_py
# convert to list of arrays
= dat_py.values.tolist()
dat_list
import rpack
import pandas as pd
import numpy as np
= rpack.pack(dat_list)
positions
= pd.DataFrame(np.row_stack(positions))
positions =['x_coord', 'y_coord']
positions.columns
= pd.concat([positions.reset_index(drop=True), dat_py], axis=1) positions
Visualization
Port the python results back to R and visualize.
library(reticulate)
Warning: package 'reticulate' was built under R version 4.2.2
library(ggplot2)
Warning: package 'ggplot2' was built under R version 4.2.2
library(showtext)
library(ggtext)
<- py$positions
data_coord
# combine the two dataframes
#data_final <- cbind(dat, data_coord)
$x_end = data_coord$x_coord + data_coord$side_x
data_coord$y_end = data_coord$y_coord + data_coord$side_y
data_coord# this is slightly stupid, but whatever. recalculate the area
$area <- data_coord$side_x * data_coord$side_y
data_coord
<- c(
color_scale "#271220",
"#24101e",
"#574557",
"#a192ad",
"#e0d3f3",
"#e0c8e5"
)
font_add_google(name = 'Major Mono Display', family = 'MajorMono')
showtext_auto()
ggplot() +
geom_rect(data = data_coord,
aes(xmin = x_coord, ymin = y_coord,
xmax = x_end, ymax = y_end,
fill = log(area)), color = '#F2eef8',
linewidth = .08) +
scale_fill_gradientn(colours=rev(color_scale)) +
labs(title = '1,000 BUILDING FOOTPRINTS',
caption = 'Each square represents the area of one of 1,000 randomly sampled building footprints in slovenia. <br>Plotted with rectangle-packer. Data: eubucco.\t') +
coord_fixed() +
theme_void() +
theme(legend.position = 'none',
plot.background = element_rect(fill = '#F2eef8', color = NA),
plot.title = element_text(size = 130, family = 'MajorMono',
color = '#271220', hjust = 0.5),
plot.caption = element_markdown(lineheight = .4,
size = 36,
family = 'MajorMono',
color = '#271220'))
ggsave('day_29_monochrome.png', width = 12, height = 8, dpi = 300)