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.
@@ -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.
@@ -0,0 +1,9 @@
1
+ include LICENSE
2
+ include README.md
3
+ include CHANGELOG.md
4
+ include CITATION.cff
5
+ include pyproject.toml
6
+ include src/landmix/py.typed
7
+ recursive-include src/landmix *.py
8
+ recursive-include tests *.py
9
+ recursive-include examples *.py *.csv *.geojson
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
+ [![PyPI version](https://img.shields.io/pypi/v/landmix.svg)](https://pypi.org/project/landmix/)
42
+ [![Python versions](https://img.shields.io/pypi/pyversions/landmix.svg)](https://pypi.org/project/landmix/)
43
+ [![CI](https://github.com/YusufEminoglu/landmix_sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/YusufEminoglu/landmix_sdk/actions/workflows/ci.yml)
44
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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`.