landmix 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- landmix-0.1.0/CHANGELOG.md +26 -0
- landmix-0.1.0/CITATION.cff +20 -0
- landmix-0.1.0/LICENSE +21 -0
- landmix-0.1.0/MANIFEST.in +9 -0
- landmix-0.1.0/PKG-INFO +317 -0
- landmix-0.1.0/README.md +279 -0
- landmix-0.1.0/examples/quickstart.py +53 -0
- landmix-0.1.0/examples/zones.csv +5 -0
- landmix-0.1.0/pyproject.toml +117 -0
- landmix-0.1.0/setup.cfg +4 -0
- landmix-0.1.0/src/landmix/__init__.py +132 -0
- landmix-0.1.0/src/landmix/__main__.py +7 -0
- landmix-0.1.0/src/landmix/_version.py +1 -0
- landmix-0.1.0/src/landmix/categories.py +252 -0
- landmix-0.1.0/src/landmix/cli.py +327 -0
- landmix-0.1.0/src/landmix/geo.py +695 -0
- landmix-0.1.0/src/landmix/indices.py +545 -0
- landmix-0.1.0/src/landmix/io.py +170 -0
- landmix-0.1.0/src/landmix/py.typed +0 -0
- landmix-0.1.0/src/landmix/report.py +263 -0
- landmix-0.1.0/src/landmix.egg-info/PKG-INFO +317 -0
- landmix-0.1.0/src/landmix.egg-info/SOURCES.txt +29 -0
- landmix-0.1.0/src/landmix.egg-info/dependency_links.txt +1 -0
- landmix-0.1.0/src/landmix.egg-info/entry_points.txt +2 -0
- landmix-0.1.0/src/landmix.egg-info/requires.txt +12 -0
- landmix-0.1.0/src/landmix.egg-info/top_level.txt +1 -0
- landmix-0.1.0/tests/conftest.py +59 -0
- landmix-0.1.0/tests/test_categories_cli.py +220 -0
- landmix-0.1.0/tests/test_geo.py +258 -0
- landmix-0.1.0/tests/test_indices.py +242 -0
- landmix-0.1.0/tests/test_io_report.py +145 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-11-09
|
|
8
|
+
### Added
|
|
9
|
+
- Indices: Shannon entropy, normalised entropy index (K = all study categories or
|
|
10
|
+
categories present), Cervero & Kockelman (1997) mean-of-cells entropy,
|
|
11
|
+
Herfindahl-Hirschman (fraction or percent scale) and normalised HHI, Simpson's lambda,
|
|
12
|
+
Gini-Simpson, Simpson's finite-sample form for counts, Hill numbers of any order and
|
|
13
|
+
Hill profiles, balance index, jobs-housing ratio and balance (Ewing et al. 2002),
|
|
14
|
+
Hoek's MXI, a provisional Bordoloi et al. (2013) area index, and the Cervero &
|
|
15
|
+
Kockelman (1997) dissimilarity index on a grid of dominant uses.
|
|
16
|
+
- Inputs: dicts, wide or long CSV (delimiter sniffing, BOM, decimal comma), optional
|
|
17
|
+
pandas DataFrames.
|
|
18
|
+
- GeoJSON: pure-Python point-in-polygon with holes and multipolygons, planar and
|
|
19
|
+
spherical areas, centroids; aggregation to zone polygons, to a regular grid and to
|
|
20
|
+
circular moving windows (Euclidean or haversine); exact area splitting with optional
|
|
21
|
+
shapely.
|
|
22
|
+
- OpenStreetMap tag classification into planning land uses with an editable mapping,
|
|
23
|
+
and category recoding.
|
|
24
|
+
- Reports: per-zone index tables with balance columns, summaries, CSV, JSON, Markdown
|
|
25
|
+
and GeoJSON output.
|
|
26
|
+
- CLI: `landmix table`, `landmix geojson`, `landmix indices`, `landmix osm-mapping`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite it as below."
|
|
3
|
+
authors:
|
|
4
|
+
- family-names: "Eminoğlu"
|
|
5
|
+
given-names: "Yusuf"
|
|
6
|
+
email: "geospacephilo@gmail.com"
|
|
7
|
+
orcid: "https://orcid.org/0009-0005-6000-2934"
|
|
8
|
+
title: "landmix"
|
|
9
|
+
version: "0.1.0"
|
|
10
|
+
date-released: "2026-11-09"
|
|
11
|
+
license: "MIT"
|
|
12
|
+
repository-code: "https://github.com/YusufEminoglu/landmix_sdk"
|
|
13
|
+
url: "https://pypi.org/project/landmix/"
|
|
14
|
+
abstract: "Land-use mix and diversity indices for urban analysis: normalised entropy (Cervero & Kockelman, Frank et al.), Herfindahl-Hirschman, Simpson and Gini-Simpson, Hill numbers, balance and jobs-housing balance, and the dissimilarity index, for zones, regular grids and moving windows built from CSV tables or GeoJSON, with OpenStreetMap category mapping."
|
|
15
|
+
keywords:
|
|
16
|
+
- land-use mix
|
|
17
|
+
- entropy
|
|
18
|
+
- diversity index
|
|
19
|
+
- urban planning
|
|
20
|
+
- gis
|
landmix-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yusuf Eminoğlu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
landmix-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: landmix
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Land-use mix and diversity indices for urban analysis: normalised entropy, Herfindahl-Hirschman, Simpson, Hill numbers, balance, jobs-housing and dissimilarity indices for zones, grids and moving windows, with OpenStreetMap category mapping.
|
|
5
|
+
Author-email: Yusuf Eminoğlu <geospacephilo@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/YusufEminoglu/landmix_sdk
|
|
8
|
+
Project-URL: Repository, https://github.com/YusufEminoglu/landmix_sdk
|
|
9
|
+
Project-URL: Issues, https://github.com/YusufEminoglu/landmix_sdk/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/YusufEminoglu/landmix_sdk/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: land-use-mix,mixed-use,entropy,diversity-index,herfindahl,simpson,hill-numbers,jobs-housing-balance,urban-planning,walkability,openstreetmap,geojson,gis
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Environment :: Console
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
22
|
+
Classifier: Intended Audience :: Science/Research
|
|
23
|
+
Classifier: Intended Audience :: Developers
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.9
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Provides-Extra: pandas
|
|
29
|
+
Requires-Dist: pandas>=1.3.0; extra == "pandas"
|
|
30
|
+
Provides-Extra: shapely
|
|
31
|
+
Requires-Dist: shapely>=2.0.0; extra == "shapely"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
36
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# landmix
|
|
40
|
+
|
|
41
|
+
[](https://pypi.org/project/landmix/)
|
|
42
|
+
[](https://pypi.org/project/landmix/)
|
|
43
|
+
[](https://github.com/YusufEminoglu/landmix_sdk/actions/workflows/ci.yml)
|
|
44
|
+
[](LICENSE)
|
|
45
|
+
|
|
46
|
+
**Land-use mix and diversity indices for urban analysis.**
|
|
47
|
+
|
|
48
|
+
`landmix` computes the land-use mix measures used in planning, transport and
|
|
49
|
+
walkability research from the amount of each land use in a zone. It runs on the
|
|
50
|
+
Python standard library alone. The indices are:
|
|
51
|
+
|
|
52
|
+
- **Entropy**: normalised Shannon entropy, with K set to all study categories
|
|
53
|
+
(Cervero & Kockelman 1997; Frank et al. 2004, 2005) or to the categories present.
|
|
54
|
+
The Cervero & Kockelman mean-of-hectares form is also included.
|
|
55
|
+
- **Concentration**: Herfindahl–Hirschman, normalised HHI, Simpson's λ, Gini–Simpson,
|
|
56
|
+
and Simpson's finite-sample form for counts.
|
|
57
|
+
- **Hill numbers**: the effective number of land uses for any order *q*.
|
|
58
|
+
- **Two-use balance**: the balance index, jobs–housing ratio and jobs–housing balance
|
|
59
|
+
(Ewing et al. 2002), and Hoek's MXI.
|
|
60
|
+
- **Spatial**: the Cervero & Kockelman (1997) dissimilarity index on a grid of
|
|
61
|
+
dominant uses.
|
|
62
|
+
|
|
63
|
+
You can read inputs from a dict, a CSV file (wide or long layout) or a pandas
|
|
64
|
+
DataFrame. GeoJSON points and polygons can be aggregated to zone polygons, to a
|
|
65
|
+
regular grid or to moving-window buffers. This uses pure-Python point-in-polygon,
|
|
66
|
+
or exact area splitting if shapely is installed. OpenStreetMap tags can be
|
|
67
|
+
classified into planning land uses. Results are written to CSV, JSON, Markdown or
|
|
68
|
+
GeoJSON from Python or the `landmix` command.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install landmix # stdlib only
|
|
72
|
+
pip install "landmix[shapely]" # + exact polygon/zone intersection
|
|
73
|
+
pip install "landmix[pandas]" # + DataFrame in/out
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Requires Python 3.9 or newer.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Quick start (Python)
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from landmix import entropy_index, hhi, hill_number, mix_table, Balance
|
|
84
|
+
|
|
85
|
+
USES = ["residential", "commercial", "office", "institutional", "entertainment"]
|
|
86
|
+
zone = {"residential": 6000, "commercial": 2500, "office": 1500} # m2 floor area
|
|
87
|
+
|
|
88
|
+
entropy_index(zone, USES) # 0.583 (K = 5 study categories)
|
|
89
|
+
entropy_index(zone, normalization="present") # 0.853 (K = 3 uses present)
|
|
90
|
+
hhi(zone) # 0.445
|
|
91
|
+
hill_number(zone, q=1) # 2.554 effective land uses
|
|
92
|
+
|
|
93
|
+
zones = {
|
|
94
|
+
"Centre": {"residential": 12000, "commercial": 9000, "office": 15000, "jobs": 1400, "housing": 300},
|
|
95
|
+
"Suburb": {"residential": 45000, "commercial": 500, "jobs": 40, "housing": 700},
|
|
96
|
+
}
|
|
97
|
+
rows = mix_table(zones, USES, balances=[Balance("jhb", ["jobs"], ["housing"])])
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`mix_table` returns one dict per zone. The default columns are `total`, `richness`,
|
|
101
|
+
`entropy`, `entropy_present`, `hhi`, `gini_simpson`, `hill1`, `hill2`,
|
|
102
|
+
`dominant_share` and `dominant`, plus `<name>` and `<name>_ratio` for each
|
|
103
|
+
`Balance`. Categories that are not listed in `USES` (here `jobs`, `housing`) are
|
|
104
|
+
left out of the mix indices, but a balance can still use them.
|
|
105
|
+
|
|
106
|
+
### GeoJSON: zones, grid, moving windows
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from landmix import (load_geojson, aggregate_to_zones, aggregate_to_grid,
|
|
110
|
+
moving_window, grid_centres, features_bounds,
|
|
111
|
+
osm_category, dissimilarity_index, mix_table)
|
|
112
|
+
|
|
113
|
+
pois = load_geojson("osm_pois.geojson") # projected CRS, metres
|
|
114
|
+
zones = load_geojson("neighbourhoods.geojson")
|
|
115
|
+
|
|
116
|
+
table = aggregate_to_zones(pois, zones, category=osm_category, zone_id="name")
|
|
117
|
+
rows = mix_table(table)
|
|
118
|
+
|
|
119
|
+
grid = aggregate_to_grid(pois, 100, category=osm_category) # 1 ha cells
|
|
120
|
+
di = dissimilarity_index(grid.dominant()) # Cervero & Kockelman
|
|
121
|
+
|
|
122
|
+
centres = grid_centres(features_bounds(pois), 200)
|
|
123
|
+
windows = moving_window(pois, centres, radius=400, category=osm_category)
|
|
124
|
+
|
|
125
|
+
# polygons by floor area property, split exactly across zones (needs shapely)
|
|
126
|
+
blocks = load_geojson("blocks.geojson")
|
|
127
|
+
table = aggregate_to_zones(blocks, zones, category="use", measure="floor_area",
|
|
128
|
+
method="intersection", zone_id="name")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`measure` is `"count"`, `"area"` (polygon area) or the name of a numeric property.
|
|
132
|
+
`category` is a property name or a function of the feature properties.
|
|
133
|
+
|
|
134
|
+
## Quick start (command line)
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# wide CSV: zone,residential,commercial,office,...,jobs,housing
|
|
138
|
+
landmix table zones.csv --categories residential,commercial,office,institutional,entertainment \
|
|
139
|
+
--balance jhb=jobs/housing -o mix.csv
|
|
140
|
+
|
|
141
|
+
# long CSV: zone,category,value
|
|
142
|
+
landmix table parcels.csv --layout long --zone-col mahalle --category-col use --value-col m2
|
|
143
|
+
|
|
144
|
+
# OSM points aggregated to zone polygons, written back as GeoJSON with the indices
|
|
145
|
+
landmix geojson pois.geojson --osm --zones zones.geojson --zone-id name -o zones_mix.geojson
|
|
146
|
+
|
|
147
|
+
# 100 m grid (prints the dissimilarity index), 400 m moving windows every 200 m
|
|
148
|
+
landmix geojson landuse.geojson --category-field use --measure area --grid 100 -o grid.geojson
|
|
149
|
+
landmix geojson pois.geojson --osm --window 400 --spacing 200 -o windows.csv
|
|
150
|
+
|
|
151
|
+
landmix indices # list indices and their sources
|
|
152
|
+
landmix osm-mapping # print the default OSM tag table (JSON) to copy and edit
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The output format follows the extension (`.csv`, `.json`, `.md`, `.geojson`).
|
|
156
|
+
Without `-o`, a Markdown table is printed. `--balance NAME=X1+X2/Y1@ratio` adds a
|
|
157
|
+
balance column. When the ratio is left out, the study-wide ratio is the target.
|
|
158
|
+
|
|
159
|
+
## API overview
|
|
160
|
+
|
|
161
|
+
| Function | Formula / meaning |
|
|
162
|
+
|---|---|
|
|
163
|
+
| `shannon(a, base=e)` | H = −Σ pⱼ ln pⱼ |
|
|
164
|
+
| `entropy_index(a, categories, k=None, normalization="all"\|"present")` | H / ln K |
|
|
165
|
+
| `cervero_kockelman_entropy(cells, categories)` | mean of cell entropies over developed cells |
|
|
166
|
+
| `hhi(a, scale=1)`, `normalized_hhi(a, k)` | Σ (s·pⱼ)²; (HHI − 1/K)/(1 − 1/K) |
|
|
167
|
+
| `simpson(a)`, `gini_simpson(a)` | λ = Σ pⱼ²; 1 − λ |
|
|
168
|
+
| `simpson_unbiased(counts)`, `gini_simpson_unbiased(counts)` | Σ nⱼ(nⱼ−1) / N(N−1) |
|
|
169
|
+
| `hill_number(a, q)`, `hill_profile(a, qs)` | ᵠD = (Σ pⱼ^q)^(1/(1−q)); q→1: exp H; q=∞: 1/max p |
|
|
170
|
+
| `balance_index(x, y, a=1)` | 1 − \|x − a·y\| / (x + a·y) |
|
|
171
|
+
| `jobs_housing_ratio(J, H)`, `jobs_housing_balance(J, H, J*, H*)` | J/H; 1 − \|J − kH\|/(J + kH), k = J*/H* |
|
|
172
|
+
| `mixed_use_index_hoek(a, housing)` | MXI = 100 · housing GFA / total GFA |
|
|
173
|
+
| `area_index(a, relevant)` | share of zone area in purpose-relevant uses (see Limitations) |
|
|
174
|
+
| `dissimilarity_index(grid, neighbours=8, edge="valid"\|"fixed")` | (1/K) Σₖ Σₗ Xₗ / 8 |
|
|
175
|
+
| `richness(a)`, `dominant_share(a)`, `proportions(a)` | helpers |
|
|
176
|
+
|
|
177
|
+
Here `a` is a `{category: amount}` mapping or a sequence of amounts. Pass
|
|
178
|
+
`categories` so that categories missing from a zone count as zero and every zone
|
|
179
|
+
shares the same K. Negative, NaN or infinite amounts raise `ValueError`. A zone
|
|
180
|
+
with a total of zero returns NaN. A zone with one land use has entropy 0, HHI 1
|
|
181
|
+
and Gini–Simpson 0.
|
|
182
|
+
|
|
183
|
+
Other modules:
|
|
184
|
+
|
|
185
|
+
- `landmix.io`: `read_csv`, `from_records`, `from_dataframe`, `to_dataframe`.
|
|
186
|
+
- `landmix.geo`: `load_geojson`, `point_in_polygon`, `geometry_area` (planar or
|
|
187
|
+
spherical), `geometry_centroid`, `aggregate_to_zones`, `aggregate_to_grid` →
|
|
188
|
+
`Grid` (`zone_table()`, `dominant()`, `to_geojson()`), `moving_window`,
|
|
189
|
+
`grid_centres`, `haversine`.
|
|
190
|
+
- `landmix.categories`: `classify_osm`, `OSM_DEFAULT_MAPPING`, `default_mapping()`,
|
|
191
|
+
`recode`, and `FRANK_CLASSES` (the five Frank et al. land uses).
|
|
192
|
+
- `landmix.report`: `mix_table`, `Balance`, `summary`, `to_markdown`, `to_json`,
|
|
193
|
+
`write_csv`.
|
|
194
|
+
|
|
195
|
+
## Method notes and sources
|
|
196
|
+
|
|
197
|
+
**Normalised entropy.** `LUM = −Σⱼ pⱼ ln pⱼ / ln K`. Cervero & Kockelman (1997) and
|
|
198
|
+
Frank et al. (2004, 2005) take *K* as the number of land-use categories in the
|
|
199
|
+
study, so a zone reaches 1 only when every study use has an equal share. This is
|
|
200
|
+
`normalization="all"`. Here a missing category matters, so give the full
|
|
201
|
+
`categories` list or `k`. Dividing by the number of uses *present*
|
|
202
|
+
(`normalization="present"`) measures evenness among those uses only. Song, Merlin &
|
|
203
|
+
Rodriguez (2013) discuss how sensitive the entropy index is to this choice. The
|
|
204
|
+
original Cervero & Kockelman entropy averages the per-hectare entropy over the
|
|
205
|
+
actively developed hectares of a tract (`cervero_kockelman_entropy`).
|
|
206
|
+
|
|
207
|
+
**Dissimilarity index** (Cervero & Kockelman 1997). For each developed hectare,
|
|
208
|
+
this is the share of its 8 neighbours whose land use differs from the centre's,
|
|
209
|
+
averaged over hectares. Build the input with `aggregate_to_grid(...).dominant()`.
|
|
210
|
+
The published form divides by 8. The default here (`edge="valid"`) divides by the
|
|
211
|
+
number of developed neighbours that exist, so that cells on the edge of the study
|
|
212
|
+
area are not penalised. Use `edge="fixed"` for the published denominator.
|
|
213
|
+
|
|
214
|
+
**HHI and Simpson.** HHI = Σ pⱼ² (Hirschman 1964; Rhoades 1993), which is
|
|
215
|
+
Simpson's λ (Simpson 1949). Gini–Simpson 1 − λ is the probability that two random
|
|
216
|
+
units of land belong to different uses. For counts of discrete units, Simpson's
|
|
217
|
+
finite-sample form Σ n(n−1)/N(N−1) avoids the small-sample bias.
|
|
218
|
+
|
|
219
|
+
**Hill numbers** (Hill 1973; Jost 2006) express diversity as an effective number
|
|
220
|
+
of equally common uses: order 0 is richness, order 1 is exp(H) and order 2 is the
|
|
221
|
+
inverse Simpson index. Simons (2023) argues for them in pedestrian-scale
|
|
222
|
+
mixed-use analysis.
|
|
223
|
+
|
|
224
|
+
**Balance and jobs–housing.** The balance index
|
|
225
|
+
`1 − |X − aY| / (X + aY)` equals 1 when `X/Y` equals the target ratio `a` and 0
|
|
226
|
+
when one of the uses is absent. Ewing, Pendall & Chen (2002) use the regional
|
|
227
|
+
jobs-per-resident ratio as the target. `mix_table` uses the study-wide ratio
|
|
228
|
+
unless `a` is given. Cervero (1989) discusses jobs–housing ratios.
|
|
229
|
+
|
|
230
|
+
**MXI** (van den Hoek 2008) is the housing share of gross floor area, in percent.
|
|
231
|
+
|
|
232
|
+
**Areas and distances.** Coordinates are planar by default, so reproject to a
|
|
233
|
+
local metric CRS. With `lonlat=True`, polygon areas use the spherical formula of
|
|
234
|
+
Chamberlain & Duquette (2007) with the WGS84 equatorial radius, and window
|
|
235
|
+
distances use the haversine formula with the mean Earth radius (6371008.8 m).
|
|
236
|
+
|
|
237
|
+
**OSM categories.** The default table follows the OSM wiki definitions of
|
|
238
|
+
`landuse`, `amenity`, `shop`, `office`, `leisure`, `tourism`, `craft` and
|
|
239
|
+
`building`. Keys are tried in a fixed priority order, so a `shop=*` on an apartment
|
|
240
|
+
building counts as commercial. The wiki defines `landuse=commercial` as
|
|
241
|
+
predominantly offices, so it maps to `office`, and `landuse=retail` maps to
|
|
242
|
+
`commercial`. The table is a judgement call: copy `default_mapping()`, edit it and
|
|
243
|
+
pass it to `classify_osm`.
|
|
244
|
+
|
|
245
|
+
### References
|
|
246
|
+
|
|
247
|
+
- Bordoloi, R., Mote, A., Sarkar, P. P., & Mallikarjuna, C. (2013). Quantification of land use diversity in the context of mixed land use. *Procedia – Social and Behavioral Sciences*, 104, 563–572. https://doi.org/10.1016/j.sbspro.2013.11.150
|
|
248
|
+
- Cervero, R. (1989). Jobs-housing balancing and regional mobility. *Journal of the American Planning Association*, 55(2), 136–150.
|
|
249
|
+
- Cervero, R., & Kockelman, K. (1997). Travel demand and the 3Ds: Density, diversity, and design. *Transportation Research Part D*, 2(3), 199–219.
|
|
250
|
+
- Chamberlain, R. G., & Duquette, W. H. (2007). *Some algorithms for polygons on a sphere*. JPL Publication 07-03.
|
|
251
|
+
- Ewing, R., Pendall, R., & Chen, D. (2002). *Measuring Sprawl and Its Impact*. Smart Growth America.
|
|
252
|
+
- Frank, L. D., Andresen, M. A., & Schmid, T. L. (2004). Obesity relationships with community design, physical activity, and time spent in cars. *American Journal of Preventive Medicine*, 27(2), 87–96.
|
|
253
|
+
- Frank, L. D., Schmid, T. L., Sallis, J. F., Chapman, J., & Saelens, B. E. (2005). Linking objectively measured physical activity with objectively measured urban form. *American Journal of Preventive Medicine*, 28(2S2), 117–125.
|
|
254
|
+
- Hill, M. O. (1973). Diversity and evenness: a unifying notation and its consequences. *Ecology*, 54(2), 427–432.
|
|
255
|
+
- Hirschman, A. O. (1964). The paternity of an index. *American Economic Review*, 54(5), 761.
|
|
256
|
+
- Iannillo, A., & Fasolino, I. (2021). Land-use mix and urban sustainability: Benefits and indicators analysis. *Sustainability*, 13(23), 13460. https://doi.org/10.3390/su132313460 (used as a published test case)
|
|
257
|
+
- Jost, L. (2006). Entropy and diversity. *Oikos*, 113(2), 363–375.
|
|
258
|
+
- Rhoades, S. A. (1993). The Herfindahl-Hirschman index. *Federal Reserve Bulletin*, 79, 188–189.
|
|
259
|
+
- Shannon, C. E. (1948). A mathematical theory of communication. *Bell System Technical Journal*, 27(3), 379–423.
|
|
260
|
+
- Simons, G. D. (2023). The cityseer Python package for pedestrian-scale network-based urban analysis. *Environment and Planning B*, 50(5), 1328–1344.
|
|
261
|
+
- Simpson, E. H. (1949). Measurement of diversity. *Nature*, 163, 688.
|
|
262
|
+
- Song, Y., Merlin, L., & Rodriguez, D. (2013). Comparing measures of urban land use mix. *Computers, Environment and Urban Systems*, 42, 1–13.
|
|
263
|
+
- van den Hoek, J. W. (2008). The MXI (Mixed-use Index) as tool for urban planning and analysis. In *Corporations and Cities*, TU Delft.
|
|
264
|
+
|
|
265
|
+
## Testing
|
|
266
|
+
|
|
267
|
+
The test suite checks every index against hand-computed values. Examples
|
|
268
|
+
include shares (0.5, 0.25, 0.25), checkerboard grids for the dissimilarity
|
|
269
|
+
index, and an exact graticule cell for the spherical area. Edge cases covered
|
|
270
|
+
are single categories, all-zero zones, missing categories and invalid amounts.
|
|
271
|
+
The suite also reproduces the published two-decimal values of Iannillo &
|
|
272
|
+
Fasolino (2021, Table 6) for Shannon–Wiener, entropy and HHI.
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
pip install -e ".[dev,pandas,shapely]"
|
|
276
|
+
python -m pytest
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Limitations
|
|
280
|
+
|
|
281
|
+
- **Bordoloi et al. (2013).** The paper proposes modified dissimilarity and entropy
|
|
282
|
+
indices, a per-trip-purpose *Area Index* and a *Mix type Index*. The full text
|
|
283
|
+
could not be consulted for this release, so only `area_index` is provided. It
|
|
284
|
+
implements the paper's description: the share of zone land in uses relevant to
|
|
285
|
+
one trip purpose. It is **not verified against the paper's equation**. The Mix
|
|
286
|
+
type Index is not implemented.
|
|
287
|
+
- The dissimilarity index uses the dominant use of each cell. How edge cells and
|
|
288
|
+
undeveloped (`None`) neighbours are treated is a documented choice (`edge=`).
|
|
289
|
+
- With `method="centroid"`, a polygon goes whole to the zone or cell containing its
|
|
290
|
+
centroid, and the centroid of a strongly concave polygon can fall outside it.
|
|
291
|
+
Use `method="intersection"` (shapely) for exact area splitting.
|
|
292
|
+
- A point exactly on a shared zone edge goes to the zone on its right or upper
|
|
293
|
+
side, the same rule the grid uses.
|
|
294
|
+
- Moving windows are straight-line (Euclidean or haversine) buffers on feature
|
|
295
|
+
representative points. Network buffers are out of scope.
|
|
296
|
+
- The grid is built in coordinate units. Grids in longitude/latitude have cells of
|
|
297
|
+
unequal area.
|
|
298
|
+
- The OSM category table is not a standard and should be reviewed for each study.
|
|
299
|
+
|
|
300
|
+
## License
|
|
301
|
+
|
|
302
|
+
MIT © 2026 Yusuf Eminoğlu. See [LICENSE](LICENSE). To cite landmix, see
|
|
303
|
+
[CITATION.cff](CITATION.cff).
|
|
304
|
+
|
|
305
|
+
## Academic citation
|
|
306
|
+
|
|
307
|
+
```bibtex
|
|
308
|
+
@software{eminoglu_landmix,
|
|
309
|
+
author = {Eminoğlu, Yusuf},
|
|
310
|
+
title = {landmix},
|
|
311
|
+
year = {2026},
|
|
312
|
+
version = {0.1.0},
|
|
313
|
+
url = {https://github.com/YusufEminoglu/landmix_sdk}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
See also `CITATION.cff`.
|