Turn your COG files into an analysis-ready time-series data cube
Project description
PixelQuery
Turn your COG files into an analysis-ready time-series data cube. No infrastructure required.
What is PixelQuery?
PixelQuery converts a directory of Cloud-Optimized GeoTIFFs (COGs) into a queryable time-series data cube backed by Icechunk virtual Zarr storage.
- Zero data copy: Virtual references to original COGs (no duplication)
- Fast ingestion: ~9ms per COG (243 files in 2 seconds)
- Lazy loading: Data reads from COGs only when you call
.compute() - pip install: No STAC server, no database, no infrastructure
- Multi-satellite: Built-in product profiles for Planet, Sentinel-2, Landsat
Quick Start
pip install pixelquery[icechunk]
import pixelquery as pq
# Ingest COGs from a directory
result = pq.ingest("./my_cogs/", band_names=["blue", "green", "red", "nir"])
print(f"Ingested {result.scene_count} scenes in {result.elapsed:.1f}s")
# Query as lazy xarray Dataset
ds = pq.open_xarray("./warehouse")
print(ds) # Dimensions: (time: 243, band: 4, y: 874, x: 3519)
5-Minute Tutorial
1. Inspect your COG files
import pixelquery as pq
# Check what you have
meta = pq.inspect_cog("./scene.tif")
print(meta) # CRS, bounds, bands, resolution
2. Ingest
result = pq.ingest(
"./planet_cogs/",
warehouse="./warehouse",
band_names=["blue", "green", "red", "nir"],
product_id="planet_sr",
)
3. Query
ds = pq.open_xarray("./warehouse")
# Filter by time range
from datetime import datetime
ds = pq.open_xarray(
"./warehouse",
time_range=(datetime(2024, 1, 1), datetime(2024, 12, 31)),
bands=["red", "nir"],
)
4. Compute NDVI
nir = ds["data"].sel(band="nir")
red = ds["data"].sel(band="red")
ndvi = (nir - red) / (nir + red)
ndvi.mean(dim="time").compute() # Actual COG reads happen here
5. Point time-series
ts = pq.timeseries("./warehouse", lon=127.05, lat=37.55)
ts["data"].sel(band="nir").plot() # Plot NIR time-series
Product Profiles
Register satellite product definitions for multi-product warehouses:
pq.register_product(
"sentinel2_l2a",
bands={"blue": 1, "green": 2, "red": 3, "nir": 7},
resolution=10.0,
provider="ESA",
)
# Browse warehouse contents
cat = pq.catalog("./warehouse")
print(cat.summary())
# === PixelQuery Warehouse Summary ===
# Products: 2
#
# planet_sr (Planet)
# Scenes: 243
# Bands: blue, green, red, nir
# Resolution: 3.0m
How It Works
COG files (on disk/S3)
|
v
VirtualTIFF parser (reads byte offsets, ~3ms/file)
|
v
Icechunk repository (stores virtual chunk references)
|
v
xarray.open_zarr() (lazy loading)
|
v
.compute() → reads actual pixel data from original COGs
No data is copied during ingestion. Icechunk stores only the byte-range
references to the original COG files. Actual pixel data is read on-demand
when you call .compute() or .values.
Performance
| Operation | Result |
|---|---|
| Single COG ingest | ~3ms (virtual reference) |
| 243 COG batch | 2.1s (8.6ms/COG) |
| Storage overhead | 0.2MB for 4.4GB data |
| Metadata query | 59ms |
| Compute 6 scenes | 255ms |
Time Travel
Icechunk provides built-in versioning. Every ingest creates a snapshot.
# View history
history = pq.open_xarray("./warehouse", snapshot_id=None)
# Query at a specific point in time
cat = pq.catalog("./warehouse")
snapshots = cat.get_snapshot_history()
old_ds = pq.open_xarray("./warehouse", snapshot_id=snapshots[-1]["snapshot_id"])
API Reference
Core Functions
| Function | Description |
|---|---|
pq.ingest(source, warehouse, ...) |
Auto-scan and ingest COGs |
pq.open_xarray(warehouse, ...) |
Query as lazy xarray Dataset |
pq.timeseries(warehouse, lon, lat, ...) |
Extract point time-series |
Inspection
| Function | Description |
|---|---|
pq.inspect_cog(path) |
Read COG metadata (CRS, bounds, bands) |
pq.inspect_directory(dir) |
Scan directory for COGs |
Catalog
| Function | Description |
|---|---|
pq.catalog(warehouse) |
Get catalog for warehouse |
pq.register_product(...) |
Register a product profile |
catalog.summary() |
Formatted warehouse summary |
catalog.products() |
List product IDs |
catalog.scenes(...) |
List scenes with filters |
Installation
From PyPI
pip install pixelquery[icechunk]
From Source
git clone https://github.com/yourusername/pixelquery.git
cd pixelquery
pip install -e ".[icechunk,dev]"
When to Use PixelQuery
| Scenario | Best Tool |
|---|---|
| Private COGs -> time-series analysis | PixelQuery |
| Public satellite data catalog | STAC + stackstac |
| Enterprise cloud data platform | Arraylake |
| Planetary-scale analysis | Google Earth Engine |
PixelQuery is designed for researchers and developers who have their own COG files and want to query them as a time-series data cube without setting up any infrastructure.
Contributing
Contributions are welcome! Please open an issue or PR.
License
Apache 2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pixelquery-0.1.6.tar.gz.
File metadata
- Download URL: pixelquery-0.1.6.tar.gz
- Upload date:
- Size: 94.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
328611a0ad163a57ba6bc73f343eeb6c1e6b910ebe7af1f7f096961ced1a4356
|
|
| MD5 |
986eada50932d23be4f8765c31493948
|
|
| BLAKE2b-256 |
d4aa4bf9cf8155701f3a7af8eab3b78198aba6474369b48e3ea098163d3ddaa9
|
Provenance
The following attestation bundles were made for pixelquery-0.1.6.tar.gz:
Publisher:
release.yml on pixelquery/pixelquery
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pixelquery-0.1.6.tar.gz -
Subject digest:
328611a0ad163a57ba6bc73f343eeb6c1e6b910ebe7af1f7f096961ced1a4356 - Sigstore transparency entry: 966246186
- Sigstore integration time:
-
Permalink:
pixelquery/pixelquery@a6b16bf34877f7c6b92d4b48797d8e5b2e4e3a0b -
Branch / Tag:
refs/tags/v0.1.6 - Owner: https://github.com/pixelquery
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a6b16bf34877f7c6b92d4b48797d8e5b2e4e3a0b -
Trigger Event:
push
-
Statement type:
File details
Details for the file pixelquery-0.1.6-py3-none-any.whl.
File metadata
- Download URL: pixelquery-0.1.6-py3-none-any.whl
- Upload date:
- Size: 115.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
46501470089c47af7b53d374f9a8b12cce1b225e71b56d894c6dcd487cfe2990
|
|
| MD5 |
6b65e50c873946f6d8197fb89369cc89
|
|
| BLAKE2b-256 |
2a9b0918b7ad260e73eee22ac796a0f9b22c72554bd00a07ad2f70de4d83d3e6
|
Provenance
The following attestation bundles were made for pixelquery-0.1.6-py3-none-any.whl:
Publisher:
release.yml on pixelquery/pixelquery
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pixelquery-0.1.6-py3-none-any.whl -
Subject digest:
46501470089c47af7b53d374f9a8b12cce1b225e71b56d894c6dcd487cfe2990 - Sigstore transparency entry: 966246278
- Sigstore integration time:
-
Permalink:
pixelquery/pixelquery@a6b16bf34877f7c6b92d4b48797d8e5b2e4e3a0b -
Branch / Tag:
refs/tags/v0.1.6 - Owner: https://github.com/pixelquery
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a6b16bf34877f7c6b92d4b48797d8e5b2e4e3a0b -
Trigger Event:
push
-
Statement type: