explore_moran_over_time

explore_moran_over_time(
    df,
    var,
    *,
    gdf,
    w=None,
    entity=None,
    time=None,
    permutations=999,
    seed=12345,
    title=None,
)

Track global Moran’s I in var period by period on a fixed entity set.

The long panel is pivoted to one row per entity and one column per period, and a single entity set — the entities with complete data across every kept period — is used throughout, so the same (possibly restricted) weights apply to every period and the Moran’s I values are comparable over time. Periods with no data at all and entities with incomplete series are dropped with a note. Each period’s test uses permutations conditional permutations (:class:esda.moran.Moran).

Parameters

Name Type Description Default
df pd.DataFrame Long panel holding var per (entity, period). required
var str Numeric column of df to track. required
gdf gpd.GeoDataFrame Entity geometry; must carry the same entity-id column as df. required
w W | None libpysal weights aligned to the gdf entity ids. None builds the default weights (queen contiguity for polygons, 6-nearest-neighbor otherwise) with a :class:~geometrics.GeometricsWarning. When entities drop, the weights are restricted (w_subset) and their transform re-applied. None
entity str | None Panel identifiers; default to the ids declared via :func:geometrics.set_panel. Both are required here. None
time str | None Panel identifiers; default to the ids declared via :func:geometrics.set_panel. Both are required here. None
permutations int Number of conditional permutations behind each period’s p_sim / z_sim. 999
seed int | None esda’s :class:~esda.moran.Moran draws its permutations from NumPy’s global random state and exposes no seed argument, so when seed is not None geometrics calls numpy.random.seed(seed) immediately before each period’s test — every period’s p-value is then reproducible on its own, independent of which other periods are present. None leaves the random state untouched. 12345
title str | None Figure title. Defaults to "Global Moran's I over time: <label>". None

Returns

Name Type Description
MoranOverTimeResult Frozen result with one row per period (period, moran_i, z_sim, p_sim, n_obs), the line-and-marker fig (filled markers flag p_sim < 0.05; the dashed line marks E[I] under spatial randomness) and w_spec.

Examples

Two periods on a four-cell strip with a smooth west-east gradient:

import geopandas as gpd
import pandas as pd
from shapely.geometry import box

from geometrics.dependence import explore_moran_over_time
from geometrics.weights import make_weights

gdf = gpd.GeoDataFrame(
    {"region": ["a", "b", "c", "d"]},
    geometry=[box(i, 0, i + 1, 1) for i in range(4)],
    crs="EPSG:4326",
)
df = pd.DataFrame(
    {
        "region": ["a", "b", "c", "d"] * 2,
        "year": [2000] * 4 + [2010] * 4,
        "gdppc": [1.0, 2.0, 3.0, 4.0, 1.5, 2.5, 3.5, 4.5],
    }
)
res = explore_moran_over_time(
    df, "gdppc", gdf=gdf, w=make_weights(gdf), entity="region", time="year",
    permutations=99,
)
print(res.df[["period", "n_obs"]].to_dict("list"))