q41·intermediate

How fast is my city sprawling — in built-up land and at night?

human-dimensionslandurbanization Datasets: 3 30–60 min
Find the data for your area

Draw a rectangle to pick your area of interest, then see what NASA data covers it (live, here in your browser) or download a ready-to-run notebook with your AOI pre-filled. The notebook runs in any Python environment — it needs a free Earthdata Login to fetch the data.

Current AOI: 77.4, 12.8 → 77.8, 13.2 (Bengaluru, India)

Cities grow in two ways you can see from space: the ground turns from green or bare to grey rooftops and roads, and the night gets brighter as new streets, homes, and businesses switch their lights on. NASA's **Black Marble** product (VNP46A2) gives a daily, cloud-gap-filled map of nighttime light [radiance](/glossary/radiance/) at ~500 m, so you can hold up one clear night against another a few years later and measure how much brighter your city has become. **Verified locally.** Over the Bengaluru AOI (77.4–77.8 °E, 12.8–13.2 °N), the VNP46A2 `Gap_Filled_DNB_BRDF-Corrected_NTL` field, averaged across five clear January nights, rose from about **28.3 nW/cm²/sr in 2018 to 33.4 nW/cm²/sr in 2024 — roughly an 18% increase in mean nighttime radiance** (a single best-night comparison gave +23%). The AOI was already ~96–100% "lit" in 2018, so here the growth shows up as *existing* areas getting brighter rather than dark land switching on — a reminder to read both the lit-area and the brightness signal together.

How fast is my city sprawling — in built-up land and at night?

Cities grow in two ways you can see from space: the ground turns from green or bare to grey rooftops and roads, and the night gets brighter as new streets, homes, and businesses switch their lights on. NASA’s Black Marble product (VNP46A2) gives a daily, cloud-gap-filled map of nighttime light radiance at ~500 m, so you can hold up one clear night against another a few years later and measure how much brighter your city has become.

Verified locally. Over the Bengaluru AOI (77.4–77.8 °E, 12.8–13.2 °N), the VNP46A2 Gap_Filled_DNB_BRDF-Corrected_NTL field, averaged across five clear January nights, rose from about 28.3 nW/cm²/sr in 2018 to 33.4 nW/cm²/sr in 2024 — roughly an 18% increase in mean nighttime radiance (a single best-night comparison gave +23%). The AOI was already ~96–100% “lit” in 2018, so here the growth shows up as existing areas getting brighter rather than dark land switching on — a reminder to read both the lit-area and the brightness signal together.

What you can answer

  • How bright your city is on any clear night, back to 2012 — VNP46A2 Gap_Filled_DNB_BRDF-Corrected_NTL (units nW/cm²/sr; the gap-filled field already patches cloud-blocked pixels)
  • How much brighter it got over a few years — difference two clear nights and map where the radiance rose the most (often the city’s expanding edge)
  • Where new lit land appeared — count the share of pixels above a “lit” threshold each year and watch that fraction climb as the urban footprint spreads
  • How nighttime growth lines up with built-up land — overlay daytime built-up cover from HLSL30 or the free GHSL settlement layer to separate “brighter” from genuinely “newly built”
  • Seasonal vs. real change — by always comparing the same months you avoid mistaking festival lighting or winter haze for true growth

What you can NOT answer with these datasets alone

  • What the light is for — VIIRS sees brightness, not whether it’s homes, factories, highways, or a single new stadium; you can’t read land use from radiance alone
  • Population or economic growth directly — lights correlate with both, but a brighter pixel isn’t a headcount or a GDP figure; treat it as a proxy, not a measurement
  • Whether new land is actually built up — a brighter night could be more efficient/added lighting on the same footprint; confirm real construction with daytime imagery (HLSL30, GHSL)
  • Fine within-block detail — at ~500 m a single pixel blends a city block; you can’t isolate one building or street
  • Clouds and the moon entirely — even gap-filled, persistently cloudy stretches and bright-moon nights add noise; always compare clear nights and the same lunar conditions

Code template (Python, cloud-direct)

Verified locally. VNP46A2 ships as daily HDF5 tiles. In the current (v002) files the data lives under the VIIRS_Grid_DNB_2d grid, and each tile carries its own lat/lon arrays — use them to crop to your city’s bounding box before computing anything. Values are in nW/cm²/sr.

import os, re, warnings, earthaccess, h5py, numpy as np
warnings.filterwarnings("ignore")

# load Earthdata creds from .env without `source` (passwords can break the shell)
for line in open(".env"):
    m = re.match(r'\s*(?:export\s+)?([A-Z0-9_]+)\s*=\s*(.*)\s*$', line)
    if m: os.environ.setdefault(m.group(1), m.group(2).strip().strip('"').strip("'"))
earthaccess.login(strategy="environment")   # free Earthdata Login

W, S, E, N = 77.4, 12.8, 77.8, 13.2          # your city (Bengaluru)
GRID = "HDFEOS/GRIDS/VIIRS_Grid_DNB_2d/Data Fields"
VAR  = GRID + "/Gap_Filled_DNB_BRDF-Corrected_NTL"

def mean_ntl(start, end):
    g = earthaccess.search_data(short_name="VNP46A2",
                                temporal=(start, end), bounding_box=(W, S, E, N))
    fn = str(earthaccess.download(g[:1], local_path="/tmp/ntl")[0])
    with h5py.File(fn, "r") as f:
        lat, lon = f[GRID + "/lat"][:], f[GRID + "/lon"][:]
        yi = np.where((lat >= S) & (lat <= N))[0]
        xi = np.where((lon >= W) & (lon <= E))[0]
        ds  = f[VAR]
        arr = ds[yi.min():yi.max()+1, xi.min():xi.max()+1].astype("float32")
        arr[arr == float(ds.attrs["_FillValue"][0])] = np.nan
    return float(np.nanmean(arr))

a = mean_ntl("2018-01-10", "2018-01-11")     # one clear night, 2018
b = mean_ntl("2024-01-10", "2024-01-11")     # same season, 2024
print(f"mean NTL {a:.1f} -> {b:.1f} nW/cm2/sr  ({(b-a)/a*100:+.0f}%)")

# for a robust number, average several clear nights per year (skip cloudy / bright-moon ones)
# and pair with daytime built-up cover (HLSL30 / GHSL) to tell "brighter" from "newly built"
How a scientist answers this
Parameters
Nighttime light radiance from VIIRS Black Marble VNP46A2 `Gap_Filled_DNB_BRDF-Corrected_NTL` (nW/cm²/sr, ~500 m, daily, cloud-gap-filled), summarized as AOI mean radiance and lit-area fraction; HLSL30 supplies built-up land cover and GHSL a free settlement baseline.
Method
Average several clear, moonlight-screened nights in the same calendar window per year to suppress noise, then difference annual means to map where radiance rose (often the expanding edge) and count newly lit pixels above a fixed radiance threshold; pair the brightness change with HLSL30/GHSL built-up change to separate densification from outward sprawl.
Validation
Use VNP46A2 quality/cloud flags, control for lunar illumination and seasonal snow, average multiple nights to beat down noise, and cross-check the built-up signal against GHSL/HLSL since brighter ≠ always more built-up.
In plain EnglishCompare how bright the city is on clear nights a few years apart, map where it got brighter, and check that against where new buildings appeared.

Make it yours → Set the city AOI box, the two years and the clear-night window, and the lit-pixel radiance threshold in the notebook.

Run the core method · no login

The robust trend (Theil–Sen + Mann–Kendall) at the heart of this question — runnable on synthetic data, right here. The full earthaccess code template further down does it on real NASA data (needs an Earthdata login).

editable · runs in your browser

Datasets used