Skip to main content

This repository is to download and process of NASA's Black Marble Nightlights Suite.

Project description

Nightlights

A Python toolkit for downloading, processing, and visualizing NASA's Black Marble Nightlights Suite (VIIRS) satellite data. This project provides tools to analyze nighttime light patterns over time, which can be used to study urbanization, economic activity, power outages, recovery from natural disasters, and more.

Getting Started

Prerequisites

  • Python 3.10 or higher
  • Poetry (for dependency management)
  • Access to an Earthdata Account

Setup

# Clone the repository
git clone https://github.com/jeronimoluza/nightlights.git
cd nightlights

# Install dependencies using Poetry
poetry install

Usage

1. Set up directories and parameters

from nightlights import download, plotting, process

# Define directories
download_dir = "./data/raw"
plot_dir = "./assets/"

# Define search parameters
short_name = "VNP46A3" # VIIRS Black Marble products: VNP46A2, VNP46A3, VNP46A4
start_date = "2021-11-01"
end_date = "2022-05-01"

# Define region of interest
regions = [
    "Kyiv, Ukraine",
    "Kyiv Oblast, Ukraine",
]

region_gdf = download.find_region(query=regions)
region_crs = region_gdf.crs.to_epsg()
region = region_gdf.union_all()

2. Download data

files = download.download_earthaccess(
    download_dir=download_dir,
    short_name=short_name,
    start_date=start_date,
    end_date=end_date,
    region=region,
)

# Variable names:
# "DNB_BRDF-Corrected_NTL" for VNP46A2 (daily data)
# "AllAngle_Composite_Snow_Free" for VNP46A3 (monthly data) and VNP46A4 (annual data)
variable_name = "AllAngle_Composite_Snow_Free"  

3. Create visualizations

Single Date Map

plotting.plot_nightlights(
    files,
    title="Nightlight Intensity\nKyiv City and Oblast",
    variable_name=variable_name,
    date="2021-11-01",
    output_dir=plot_dir,
    region=region,
)

Single Date Map

Time Series Lineplot with Events

import numpy as np

# Define functions to apply to the data
functions = [
    {"Mean": np.mean},
    {"Median": np.median},
]

# Define important events to mark on the plot
events = [
    ("Start of the conflict\nAttacks on Kyiv's Energy Infrastructure", "2022-02-01"),
]

plotting.create_lineplot(
    files=files,
    variable_name=variable_name,
    title="Nightlight Intensity\nKyiv City and Oblast",
    output_dir=plot_dir,
    region=region,
    region_crs=region_crs,
    functions=functions,
    events=events,
    cut_off=1, # Will only consider values higher than the cut_off parameter for the lineplot
)

Time Series Lineplot with Events

Side-by-Side Comparison

plotting.side_by_side(
    files=files,
    variable_name=variable_name,
    title="Nightlight Intensity\nKyiv City and Oblast: Pre-War vs Post-War",
    date1="2021-11-01",
    date2="2022-07-01",
    region=region,
    region_crs=region_crs,
    output_dir=plot_dir,
    bins=15,
    log_scale=True
)

Side-by-Side Comparison

Timelapse Animation

plotting.create_timelapse_gif(
    files=files,
    variable_name=variable_name,
    title="Nightlight Intensity\nKyiv City and Oblast",
    output_dir=plot_dir,
    region=region,
    region_crs=region_crs,
    fps=2.0,
)

Timelapse Animation

4. Advanced Processing: Polygonize Data

The extraction of pixel boundaries from each file involves a calculation of geographical coordinates based on the Black Marble tile's limits and file matrix dimensions. The process begins by determining the size of each tile in degrees using its west, north, east, and south bounds. Then, utilizing the matrix dimensions (rows and columns), the distances between pixel boundaries are calculated. Specifically, the distance from the west-east bounds of the tile is divided by the number of rows (X) to determine the longitude increment per pixel, while the distance from the north-south bounds is divided by the number of columns (Y) to calculate the latitude increment per pixel.

# Convert raster data to vector polygons for GIS analysis
gdf = process.polygonize(
    files, 
    variable_name=variable_name, 
    region=region, 
    region_crs=region_crs, 
    optimize_geometry=True
)

# Save the results
gdf.head()
|    | pixel_id                         | tile   | date       | variable                     |   value | geometry                                                                                                                                                                   |
|---:|:---------------------------------|:-------|:-----------|:-----------------------------|--------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|  0 | 832d7e3f2e1e1b4c082450dc2c55695b | h21v04 | 2021-11-01 | AllAngle_Composite_Snow_Free |       0 | POLYGON ((30 49.99583333333334, 30.00416666666667 49.99583333333334, 30.00416666666667 50, 30 50, 30 49.99583333333334)) |
|  1 | cc3f405d6588e83e068cf95139226b4e | h21v04 | 2021-11-01 | AllAngle_Composite_Snow_Free |       0 | POLYGON ((30.004166666666666 49.99583333333334, 30.008333333333336 49.99583333333334, 30.008333333333336 50, 30.004166666666666 50, 30.004166666666666 49.99583333333334)) |
|  2 | fbcda96016cddc5701decea68cfb2b0d | h21v04 | 2021-11-01 | AllAngle_Composite_Snow_Free |       0 | POLYGON ((30.008333333333333 49.99583333333334, 30.012500000000003 49.99583333333334, 30.012500000000003 50, 30.008333333333333 50, 30.008333333333333 49.99583333333334)) |
|  3 | ef914453eb14b7c27022450f6966e5a9 | h21v04 | 2021-11-01 | AllAngle_Composite_Snow_Free |       0 | POLYGON ((30.0125 49.99583333333334, 30.01666666666667 49.99583333333334, 30.01666666666667 50, 30.0125 50, 30.0125 49.99583333333334)) |
|  4 | a7281d42070a22a0b69de920afea3681 | h21v04 | 2021-11-01 | AllAngle_Composite_Snow_Free |       0 | POLYGON ((30.016666666666666 49.99583333333334, 30.020833333333336 49.99583333333334, 30.020833333333336 50, 30.016666666666666 50, 30.016666666666666 49.99583333333334)) |

License

MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nightlights-0.1.0.tar.gz (19.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nightlights-0.1.0-py3-none-any.whl (20.4 kB view details)

Uploaded Python 3

File details

Details for the file nightlights-0.1.0.tar.gz.

File metadata

  • Download URL: nightlights-0.1.0.tar.gz
  • Upload date:
  • Size: 19.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.13.5 Darwin/24.5.0

File hashes

Hashes for nightlights-0.1.0.tar.gz
Algorithm Hash digest
SHA256 442f8a8e364785a2cf7d1b24b23d5792504d03f403f5b6f43056a3eec0269612
MD5 749fc0a8cbbb201918a8c77440c167d8
BLAKE2b-256 c1bea53a31accc62325eda2fe4b10279f645a26eaa3905e6c45a6a02453a4273

See more details on using hashes here.

File details

Details for the file nightlights-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: nightlights-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.13.5 Darwin/24.5.0

File hashes

Hashes for nightlights-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 172afc75fe0f9be61f8d9f46e3cd77fd33bd2dd05c5f217d8ccb3239998ad3ec
MD5 ab60412f7d52459f9c02847990698f18
BLAKE2b-256 d21a24b2bc7ee893681d3d24758295a27fdafcd71b06b1e1ea06b940ee435429

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page