moveq
Transport-equity analysis for Python.
moveq turns the numbers you already have — trips per area, population
counts, deprivation ranks, coverage shares — into standard inequality
measures and a documented composite accessibility score, plus a
cross-country catalogue contract so a study cannot silently drop a
section when it moves from one country to another.
It is a library stack, not a hosted product. You bring arrays or CSVs;
moveq owns the math and the trail of what was computed. It does not
decide policy.
This package is the one most people should install. It re-exports the
public API of moveq-core and
moveq-catalogue behind
import moveq. The command-line tool is a separate install:
moveq-cli.
What it computes
Inequality of service (who gets how much). Given a service value per area (weekly trips, departures, coverage) and a population weight:
- Gini — overall inequality of that service across people.
0is equal service for everyone (including the all-zero convention); values toward1mean service is concentrated on a small share of the population. Internally this is a population-weighted Lorenz curve, integrated with the trapezoid rule. - Palma ratio — the extremes: mean service of the best-served 10%
of the population divided by mean service of the worst-served 40%.
Areas that straddle those cuts are split proportionally. Equal service,
including all-zero service, yields
1. If the bottom 40% have no service while the top 10% do not, the result is infinity.
Neither Gini nor Palma knows anything about income or deprivation. They only describe the distribution of the service variable.
Inequality along deprivation (who is favoured). The Wagstaff
Concentration Index ranks areas by a socioeconomic variable (for
example Index of Multiple Deprivation, where 1 is most deprived) and
asks whether service rises or falls along that ranking. Tied ranks share
a group-midpoint fractional rank so input order does not change the
answer. For non-negative service the index lies in [-1, 1]:
- positive — outcome concentrated among more-advantaged observations (advantage-concentrated)
- negative — outcome concentrated among less-advantaged observations (disadvantage-concentrated)
- zero — no systematic gradient with rank
A composite score that does not treat missing data as zero. Accessibility
work almost always has holes: night frequency was not collected, weekend
service is unknown for one cut. compute_score takes named terms in
[0, 1] and design weights. Any term that is None is dropped and
the remaining weights are renormalised. The result is a 0–100 score
plus a component table (design_weight vs weight_used, which terms
were dropped, and a human-readable note). If every term is missing,
the score is None rather than a silent 0.
A same / replace / omit registry for multi-country work. When a
questionnaire or indicator list is reused in a second country, some
items map cleanly, some need a local substitute, and some cannot be
measured at small-area resolution. Catalogue
requires an explicit decision for every base section so an item cannot
disappear without a record.
The methodology guide has the formulae.
Installation
Requires Python 3.10+.
pip install moveq
Pandas helpers for a vulnerability index and “multiply deprived” flags:
pip install "moveq[frames]"
CSV / JSON command line (installs this package as a dependency):
pip install moveq-cli
Quickstart
import numpy as np
from moveq import (
compute_gini,
compute_palma_ratio,
compute_concentration_index,
gini_result,
compute_score,
Catalogue,
SectionAction,
)
service = np.array([10.0, 20.0, 5.0, 50.0, 8.0])
population = np.array([1000, 800, 1200, 300, 900])
deprivation_rank = np.array([1, 3, 2, 5, 4]) # 1 = most deprived
gini = compute_gini(service, population)
palma = compute_palma_ratio(service, population)
ci = compute_concentration_index(
service, deprivation_rank, population, rank_direction="higher_is_advantaged"
)
gini_audit = gini_result(service, population) # EquityResult: value, method, n_areas, …
result = compute_score(
terms={"coverage": 0.7, "evening": 0.5, "frequency": None, "gap": 0.9},
weights={"coverage": 0.40, "evening": 0.25, "frequency": 0.20, "gap": 0.15},
)
# result.score is on 0–100; result.dropped lists terms that were None
Package layout
| PyPI project | Role |
|---|---|
moveq (this package) |
Single import for the Python API |
moveq-core |
NumPy algorithms; optional pandas extras |
moveq-catalogue |
Harmonization registry |
moveq-cli |
moveq command for CSV and JSON |
All four are versioned together.
What this stack is not
- Not a GIS toolkit, GTFS parser, or data pipeline — pass in arrays or CSVs.
- Not a dashboard or SaaS product.
- Not a legal or policy verdict. Rankings and cut-offs stay with the analyst.
Documentation
License
Metadata
Release files for moveq 0.2.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 | |
|---|---|---|---|
| moveq-0.2.0.tar.gz | 6.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| moveq-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 11.6 kB
Release files / moveq-0.2.0.tar.gz
| Download URL | moveq-0.2.0.tar.gz |
|---|---|
| Size | 6.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7bec54124a78c47de45ba571468905f4672680abc76160e913044dd5f0dbdb1f
|
|
BLAKE2b-256 checksum How to use checksums |
1d2ed9a7c4c1152af9952707f7fd4ca44ac863e7925580db9fb631e66aa88ea8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 5, 2026.
Transparency logRelease files / moveq-0.2.0-py3-none-any.whl
| Download URL | moveq-0.2.0-py3-none-any.whl |
|---|---|
| Size | 5.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
14f89bc7a989e86a721c3ace442b5ec829064b1db6a23f44e140e98c30de2b13
|
|
BLAKE2b-256 checksum How to use checksums |
2f20fa208ed01f90473c04c254637b29ec477cda146ee09c4e16e687cb3610fc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 5, 2026.
Transparency log