Practical Guides

Worked examples of Gini, Palma, and the Concentration Index on arrays you already have. moveq does not parse GTFS, aggregate to H3, route, or render maps: those belong in the tools that produce the arrays.

Core metrics

1. Inequality of a service array

The same pattern as examples/basic_equity/run.py. Service is the resource; population is the weight; rank is a socioeconomic ordering you must declare.

basic_equity.py Python 3.10+
import numpy as np
from moveq import compute_gini, compute_palma_ratio, compute_concentration_index

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; higher = more advantaged

gini = compute_gini(service, population)
palma = compute_palma_ratio(service, population)
ci = compute_concentration_index(
    service, deprivation_rank, population,
    rank_direction="higher_is_advantaged",
)

print(f"Gini: {gini:.4f}")
print(f"Palma ratio: {palma:.4f}")
print(f"Concentration Index: {ci:.4f}")
Distributional change

2. Baseline versus proposal

Compare two service arrays on the same units and rank. Interpretation, and any regulatory determination, rest with the analyst. moveq generates evidence; it does not determine compliance.

baseline_proposal.py Python 3.10+
from moveq import compute_concentration_index

# Rank: 1 = most deprived, higher = more advantaged
rank = tract_df["deprivation_rank"].values
baseline_service = tract_df["trips_2025"].values
proposed_service = tract_df["trips_2026_proposed"].values
population = tract_df["population"].values

ci_baseline = compute_concentration_index(
    baseline_service, rank, population,
    rank_direction="higher_is_advantaged",
)
ci_proposed = compute_concentration_index(
    proposed_service, rank, population,
    rank_direction="higher_is_advantaged",
)

print(f"Baseline CI: {ci_baseline:+.4f}")
print(f"Proposed CI: {ci_proposed:+.4f}")
print(f"Change in CI: {ci_proposed - ci_baseline:+.4f}")