Table of contents
Simplified building taxonomy of selected cities (animation)
What is this about?
A small-multiple grid of simplified building outlines for selected cities, built with PyData, QuackOSM, and Metaflow from OpenStreetMap geometries.
#30DayMapChallenge | Day 3: Polygons | 2024 (see: "30DayMapChallenge" official Github repo)
Recently I saw a post by Daniel Gorokhov who illustrated building taxonomy of "interesting buildings" in Milano, Italy, Stockholm, Sweden and Amsterdam, Netherlands. Here is my extension for that post, with some more cities, mostly in USA, but also in Europe.
Chart type is "small multiple" (a.k.a. "grid chart"). How was it made? I run a script that loaded all mapped buildings within city area and counted exterior vertices (nodes) for all of them. Still, I did not explicitly count inner polygons, like courtyards or patios. Then, I took one hundred of buildings with the most nodes to plot them.
- Yet, it happened that under current methodology, quite often, "interesting" buildings are repetitive because of construction nature (for example - neighborhoods of apartment buildings or high-rise housing projects; industrial structures, like water treatment ponds, fuel storages, dockside cranes)
- Yet, it happened that under current methodology, quite often, "interesting" buildings are repetitive because of construction nature (for example - neighborhoods of apartment buildings or high-rise housing projects; industrial structures, like water treatment ponds, fuel storages, dockside cranes)
Made with #Python
Data: #OSM, #OpenStreetMap retrieved with QuackOSM
#dataviz #datavisualization
How to read this?
The chart is a small multiple (grid chart). Each city is one panel. Inside each panel, the 100 buildings with the most exterior vertices are drawn as simplified outlines.
Complexity here means vertex count on the exterior ring, not architectural fame. Courtyards and other inner rings are not counted explicitly. Under this rule, "interesting" shapes often repeat: housing projects, industrial ponds, fuel storages, dockside structures, and similar construction patterns. Some truly complex buildings are also poorly mapped in OSM and need case-by-case handling (multi-buildings, connections, and similar edge cases).
Why did I make it?
I wanted to extend Daniel Gorokhov's Milano / Stockholm / Amsterdam taxonomy idea to a wider city set for #30DayMapChallenge Day 3 (Polygons), and to keep the pipeline reproducible in Python rather than as a one-off illustration.
What's under the hood?
Pipeline sketch: load OSM buildings for each city with QuackOSM, count exterior vertices, keep the top 100 per city, plot the small multiples with Matplotlib, orchestrated in Metaflow.
How-to: make this chartClick or tap to open section
★ Click to see code snippets
import metaflow
from metaflow import FlowSpec, Parameter, JSONType, step, NBRunner, pypi
import quackosm as qosm
import time
import datetime
import numpy as np
import geopandas as gpd
import matplotlib
import matplotlib.pyplot as pltPipeline sketch (Metaflow)
def _func_count_vertices(row_index, row_values_series):
"""
* https://gis.stackexchange.com/questions/328884/counting-number-of-vertices-in-geopandas
* https://gis.stackexchange.com/questions/388606/counting-vertices-and-adding-it-as-number-to-column-using-shapely
"""
geometry = row_values_series.geometry
geom_type = geometry.geom_type
n_vertices = 0
#try:
if geom_type == "Polygon":
n_vertices = len(geometry.exterior.coords)
elif geom_type == "MultiPolygon":
for inner_geometry in list(geometry.geoms):
n_vertices += len(inner_geometry.exterior.coords)
else:
None
#print("- Other type of geometry: ", geom_type, row_index)
#except:
#print("- There was unexpected error with row: ", row_index)
return n_verticesPipeline sketch (Metaflow)
def _func_count_vertices(row_index, row_values_series):
"""
* https://gis.stackexchange.com/questions/328884/counting-number-of-vertices-in-geopandas
* https://gis.stackexchange.com/questions/388606/counting-vertices-and-adding-it-as-number-to-column-using-shapely
"""
geometry = row_values_series.geometry
geom_type = geometry.geom_type
n_vertices = 0
#try:
if geom_type == "Polygon":
n_vertices = len(geometry.exterior.coords)
elif geom_type == "MultiPolygon":
for inner_geometry in list(geometry.geoms):
n_vertices += len(inner_geometry.exterior.coords)
else:
None
#print("- Other type of geometry: ", geom_type, row_index)
#except:
#print("- There was unexpected error with row: ", row_index)
return n_verticesPipeline sketch (Metaflow)
def _func_count_vertices(row_index, row_values_series):
"""
* https://gis.stackexchange.com/questions/328884/counting-number-of-vertices-in-geopandas
* https://gis.stackexchange.com/questions/388606/counting-vertices-and-adding-it-as-number-to-column-using-shapely
"""
geometry = row_values_series.geometry
geom_type = geometry.geom_type
n_vertices = 0
#try:
if geom_type == "Polygon":
n_vertices = len(geometry.exterior.coords)
elif geom_type == "MultiPolygon":
for inner_geometry in list(geometry.geoms):
n_vertices += len(inner_geometry.exterior.coords)
else:
None
#print("- Other type of geometry: ", geom_type, row_index)
#except:
#print("- There was unexpected error with row: ", row_index)
return n_verticesRelated work
- "Building taxonomy of Milano, Stockholm and Amsterdam" by Daniel Gorokhov
- "Visualizing a building shapes taxonomy - The City Summit project" by Kamil Raczycki
Media presence
How to cite
For human-readable attribution, please cite this work as:
Visualization "Building taxonomy" (2024), Vitaliy Yevtushenko (Witold's Data Consulting). https://witold1.github.io/portfolio/blog/viz-building-taxonomy/.BibTeX
@misc{witold_blog_viz-building-taxonomy,
author = {Vitaliy Yevtushenko},
title = {{Visualization "Building taxonomy"}},
year = {2024},
url = {https://witold1.github.io/portfolio/blog/viz-building-taxonomy/},
}