spacematrix
Urban density indicators after Berghauser Pont & Haupt's Spacematrix (2010).
spacematrix measures building intensity (FSI), coverage (GSI), spaciousness
(OSR), average storeys (L), network density (N) and tare (T) for lots, islands
(urban blocks), fabrics and districts from building footprints, plot/block
polygons and street centrelines. It classifies samples into Spacematrix building
types, draws the Spacemate diagram with iso-L and iso-OSR lines, and relates the
indicators to dwelling density and to the Turkish TAKS / KAKS (emsal) rules.
The core runs on the Python standard library alone (pure-Python polygon area,
exact polygon overlap and line clipping). shapely and matplotlib are optional.
pip install spacematrix # stdlib only
pip install "spacematrix[plot]" # + Spacemate diagram (matplotlib)
pip install "spacematrix[shapely]" # + shapely overlap backend
pip install "spacematrix[all]"
Requires Python 3.9 or newer.
Quick start
import spacematrix as sm
lot = sm.Zone(sm.Polygon.rectangle(0, 0, 20, 30), id="lot-1") # 600 m2
house = sm.Building(sm.Polygon.rectangle(5, 5, 15, 17), floors=3) # 120 m2 x 3
r = sm.measure(lot, [house], level="lot")
r.fsi, r.gsi, r.osr, r.l # (0.6, 0.2, 1.333, 3.0)
r.type # 'low-rise strip' (approximate thresholds, see below)
A whole hierarchy, from GeoJSON layers in a projected (metric) CRS:
buildings = sm.read_buildings("buildings.geojson", floors_field="floors") # or height_field=
res = sm.analyze(
buildings,
lots=sm.read_zones("lots.geojson"),
islands=sm.read_zones("blocks.geojson"),
fabrics=sm.read_zones("fabrics.geojson"), # bounded by street centrelines
network=sm.read_network("streets.geojson"),
)
for f in res.fabrics:
print(f.id, f.fsi, f.gsi, f.n, f.tare, f.mesh_size, f.profile_width, f.type)
sm.write_csv(res.records(), "density.csv")
The Spacemate:
from spacematrix.plot import spacemate
ax = spacemate(res.islands, type_grid=sm.DEFAULT_THRESHOLDS)
ax.figure.savefig("spacemate.png", dpi=150)
Command line
spacematrix metrics --floor-area 76800 --built-area 19200 --area 40000 \
--interior-length 400 --edge-length 800 --lower-area 25600
spacematrix grid --w 100 --b 20 # N and T of an orthogonal grid
spacematrix taks-kaks --taks 0.30 --kaks 1.50 --exempt-share 0.2 \
--island-tare 0.1 --fabric-tare 0.3
spacematrix analyze --buildings b.geojson --lots lots.geojson --islands blocks.geojson \
--fabrics fabrics.geojson --network streets.geojson --height-field height \
--out density.csv --plot spacemate.png
spacematrix diagram density.csv -o islands.png --level island
python examples/quickstart.py reproduces the worked grid example below.
API overview
| Area | Names |
|---|---|
| Inputs | Polygon, Building (floors or Building.from_height), Zone, Network, floors_from_height |
| Indicators | fsi, gsi, osr, layers, network_density, tare, upscale, mesh_size, grid_network_density, grid_tare, profile_width, fsi_from_gsi_l, fsi_from_gsi_osr |
| Measurement | measure(zone, buildings, level=..., network=..., lower_level=...), analyze(...) → SpacematrixResult, aggregate(records); records are Density objects with as_dict() |
| Types | classify(fsi, gsi, thresholds), TypeThresholds, DEFAULT_THRESHOLDS, THRESHOLDS_VERIFIED (= False) |
| Other measures | dwelling_density, coverage_percent, dwellings_from_fsi, fsi_from_dwelling_density, population_density, fsi_from_kaks, kaks_from_fsi, taks_kaks_equivalent, TAKS_KAKS_NOTE |
| Geometry / IO | shape_area, intersection_area (backend="python" or "shapely"), split_line_length, read_buildings, read_zones, read_network, write_csv, write_geojson |
| Diagram | spacematrix.plot.spacemate(samples, type_grid=..., iso_l=..., iso_osr=...) |
Method and sources
Definitions from Berghauser Pont, M. and Haupt, P. (2010), Spacematrix: Space,
Density and Urban Form, Rotterdam: NAi Publishers. F gross floor area, B
built-up (footprint) area, A plan area of level x:
| Indicator | Formula | Notes |
|---|---|---|
| FSI | F / A |
floor space index (intensity) |
| GSI | B / A |
ground space index (coverage) |
| OSR | (1 − GSI) / FSI |
unbuilt ground per m² of floor area (spaciousness) |
| L | FSI / GSI |
average number of storeys |
| N | (l_i + l_e / 2) / A_f |
m of street per m² of fabric; edge streets (on the fabric boundary) count half |
| T | (A_x − A_y) / A_x |
tare: share of level x not taken by the lower level y |
| w | 2 / N |
mesh size of the equivalent orthogonal grid |
| b | 2 (1 − √(1 − T)) / N |
profile width; inverse of T = (2bw − b²) / w² |
Levels: lot (plot) ⊂ island (block, island tare = internal paths and
communal space) ⊂ fabric (islands plus the streets around them, bounded by
street centrelines; fabric tare ≈ street space) ⊂ district (plus large parks,
water, infrastructure). Tare lowers FSI and GSI by the same factor
(FSI_x = FSI_y (1 − T_x)), so L is the same at every level.
Building floor area is footprint × floors (or a measured value). Floors can be
estimated from height with a configurable storey height (default 3.0 m, a
convention, not a standard). Buildings are allocated to zones by footprint
overlap (exact, buildings straddling a boundary are split) or by centroid.
Worked example (tested)
Orthogonal 2 × 2 grid, street centrelines every 100 m (w = 100 m), 20 m profiles (b = 20 m), 80 × 80 m islands each with a four-storey perimeter block around a 40 × 40 m courtyard:
| Level | A (m²) | FSI | GSI | OSR | L | N (m/m²) | T |
|---|---|---|---|---|---|---|---|
| island | 6 400 | 3.00 | 0.75 | 0.083 | 4 | – | – |
| fabric | 40 000 | 1.92 | 0.48 | 0.271 | 4 | 0.02 (= 2/w) | 0.36 (= (2bw−b²)/w²) |
profile_width(0.36, 0.02) = 20 m recovers b.
Building types
classify assigns one of nine types — low-/mid-/high-rise × point/strip/block —
from L (height class; bands between iso-L rays) and GSI (form class). The book
identifies these types as clusters in the Spacemate; the numeric cut-offs used
here (L ≤ 3.5 low-rise, L ≤ 7.5 mid-rise; GSI < 0.20 point, GSI < 0.35 strip,
otherwise block) are approximations that were not verified against the book.
They are fields of TypeThresholds; calibrate them to your own reference samples
or a cluster analysis (Berghauser Pont & Olsson, 2017, ISUF Valencia). Classify
island-level values: analyze classifies fabrics from their net values
FSI/(1−T), GSI/(1−T) to avoid the tare shift.
Other density measures and TAKS / KAKS
Dwelling density (dwellings/ha) depends on dwelling size and the residential
share of floor area, so dwellings_from_fsi / fsi_from_dwelling_density make
the conversion explicit. Coverage is 100 × GSI.
The Turkish Planlı Alanlar İmar Yönetmeliği (RG 30113, 3 July 2017, as amended; mevzuat.gov.tr no. 23722) defines in Article 4 TAKS = taban alanı / imar parseli alanı (cccc) and KAKS (emsal) = sum of floor areas / imar parseli alanı (tt), where floor area (katlar alanı, şş) excludes the areas of Article 22. Article 20(5) applies the base area to the net parcel and Article 5(8) caps all emsal-exempt areas at 30 % of the emsal area. Therefore:
TAKS ≈ GSI_lotandKAKS ≈ FSI_lot— both are lot-level (net) ratios;- gross
FSI_lot = KAKS × (1 + e)with exempt share0 ≤ e ≤ 0.30; - island/fabric values need the tares:
taks_kaks_equivalent(taks, kaks, exempt_share=e, island_tare=T_i, fabric_tare=T_f); - plan values are permitted maxima, not the built stock.
Limitations
- Coordinates must be projected and metric; the readers refuse data that looks
like longitude/latitude (override with
allow_geographic=True). No reprojection. - Pure-Python overlaps are O(buildings × zones) with a bounding-box filter; fine
for neighbourhoods and districts, use
backend="shapely"for larger sets. Polygons must be valid (simple rings, holes inside the exterior, parts of a multipolygon not overlapping). - Edge streets are detected as centreline pieces within
edge_tolerance(1 cm by default) of the zone boundary; draw fabric boundaries on the centrelines. - Network density at district level uses the same rule as at fabric level.
- Type thresholds are approximate (see above);
THRESHOLDS_VERIFIEDisFalse. - Floors from height assume a uniform storey height; basements are not counted.
Academic citation
@software{eminoglu_spacematrix,
author = {Eminoğlu, Yusuf},
title = {spacematrix},
year = {2026},
version = {0.1.0},
url = {https://github.com/YusufEminoglu/spacematrix_sdk}
}
Please also cite the method: Berghauser Pont, M. and Haupt, P. (2010). Spacematrix: Space, Density and Urban Form. Rotterdam: NAi Publishers.
License
MIT © 2026 Yusuf Eminoğlu. Contact: geospacephilo@gmail.com
Metadata
Release files for spacematrix 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| spacematrix-0.1.0.tar.gz | 44.8 kB | With provenance | Details for spacematrix-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| spacematrix-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for spacematrix-0.1.0-py3-none-any.whl |
Total release size: 79.8 kB
Release files / spacematrix-0.1.0.tar.gz
| Download URL | spacematrix-0.1.0.tar.gz |
|---|---|
| Size | 44.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5a9595ab460d7fdc170ad93bfcab5375b25e422b54a1d86b107eee82d80f7c95
|
|
BLAKE2b-256 checksum How to use checksums |
b6be3e962d51aa0d3ba8e605c47c2a6da01cb69fdda857760200baba827197a6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.
Transparency logRelease files / spacematrix-0.1.0-py3-none-any.whl
| Download URL | spacematrix-0.1.0-py3-none-any.whl |
|---|---|
| Size | 35.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5b6ab4dd9f00bfbed9b6deb091fb738fbec804691a5e3ea60779a166a4eebd22
|
|
BLAKE2b-256 checksum How to use checksums |
c9b9c734ef5f036c149a401785bcb96f6746e3a8b5514bb3fbd5971655ce0b9c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.
Transparency logSecurity for spacematrix 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for spacematrix-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.