Scene Discovery - Black-Lights/planetscope-py GitHub Wiki

PlanetScopeQuery Class

The PlanetScopeQuery class is your gateway to Planet's vast satellite imagery archive. It provides intelligent scene discovery with advanced filtering and batch processing capabilities.

Basic Usage

Initialize Query System

from planetscope_py import PlanetScopeQuery

# Automatic authentication (uses environment variable or credential files)
query = PlanetScopeQuery()

# Or specify API key directly
query = PlanetScopeQuery(api_key="your_planet_api_key")

Simple Scene Search

# Define area of interest - Milan, Italy
milan_point = {
    "type": "Point",
    "coordinates": [9.1900, 45.4642]  # [longitude, latitude]
}

# Search for scenes
results = query.search_scenes(
    geometry=milan_point,
    start_date="2024-01-01",
    end_date="2024-01-31",
    cloud_cover_max=0.2,  # 20% maximum cloud cover
    item_types=["PSScene"]
)

print(f"Found {len(results['features'])} scenes")

Advanced Filtering

Multiple Filter Criteria

# Complex polygon around Milan metropolitan area
milan_polygon = {
    "type": "Polygon",
    "coordinates": [[
        [8.55, 45.91],   # Northwest
        [9.83, 45.91],   # Northeast  
        [9.83, 45.02],   # Southeast
        [8.55, 45.02],   # Southwest
        [8.55, 45.91]    # Close polygon
    ]]
}

results = query.search_scenes(
    geometry=milan_polygon,
    start_date="2024-06-01", 
    end_date="2024-08-31",
    cloud_cover_max=0.15,      # 15% max cloud cover
    sun_elevation_min=30,      # Minimum sun elevation angle
    item_types=["PSScene"],
)

Supported Filter Parameters

Parameter Type Description Example
geometry Dict/Polygon Area of interest Point, Polygon, MultiPolygon
start_date str/datetime Start date (inclusive) "2024-01-01"
end_date str/datetime End date (inclusive) "2024-12-31"
cloud_cover_max float Maximum cloud cover (0.0-1.0) 0.2 for 20%
sun_elevation_min float Minimum sun elevation (degrees) 30.0
item_types List[str] Planet item types ["PSScene"]
asset_types List[str] Asset types to include ["analytic", "visual"]

Batch Operations

Process Multiple Regions

# Define multiple regions of interest
regions = [
    {"type": "Point", "coordinates": [9.19, 45.46]},    # Milan
    {"type": "Point", "coordinates": [11.26, 43.77]},   # Florence  
    {"type": "Point", "coordinates": [12.49, 41.90]}    # Rome
]

# Batch search across all regions
batch_results = query.batch_search(
    geometries=regions,
    start_date="2024-01-01",
    end_date="2024-01-15",
    cloud_cover_max=0.2
)

# Process results
for i, result in enumerate(batch_results):
    if result["success"]:
        scenes = result["result"]["features"]
        print(f"Region {i+1}: {len(scenes)} scenes found")
    else:
        print(f"Region {i+1}: Error - {result['error']}")

Scene Statistics

Get Collection Statistics

# Get statistical overview without downloading full scenes
stats = query.get_scene_stats(
    geometry=milan_polygon,
    start_date="2024-01-01",
    end_date="2024-12-31",
    interval="month"  # Monthly breakdown
)

print(f"Total scenes available: {stats['total_scenes']}")
print("Monthly distribution:", stats['temporal_distribution'])

Preview Generation

Get Scene Thumbnails

# Search for scenes
results = query.search_scenes(milan_polygon, "2024-01-01", "2024-01-31")

# Extract scene IDs
scene_ids = [scene['id'] for scene in results['features'][:5]]

# Get preview URLs
previews = query.get_scene_previews(scene_ids)

for scene_id, preview_url in previews.items():
    print(f"Scene {scene_id}: {preview_url}")

Response Structure

Search Results Format

results = {
    "features": [
        {
            "id": "scene_id_here",
            "type": "Feature",
            "geometry": {...},           # Scene footprint
            "properties": {
                "acquired": "2024-01-15T14:30:00Z",
                "cloud_cover": 0.05,
                "sun_elevation": 45.2,
                "item_type": "PSScene",
                # ... more metadata
            }
        }
    ],
    "stats": {
        "total_scenes": 42,
        "date_range": {
            "start": "2024-01-01",
            "end": "2024-01-31"
        }
    },
    "search_params": {
        "geometry": {...},
        "filters": {...}
    }
}

Error Handling

Robust Error Management

from planetscope_py.exceptions import APIError, ValidationError, RateLimitError

try:
    results = query.search_scenes(
        geometry=invalid_geometry,
        start_date="2024-01-01",
        end_date="2024-12-31"
    )
except ValidationError as e:
    print(f"Invalid input: {e.message}")
    print(f"Suggestions: {e.details.get('suggestions', [])}")
except RateLimitError as e:
    print(f"Rate limited: {e.message}")
    print(f"Retry after: {e.retry_after} seconds")
except APIError as e:
    print(f"API error: {e.message}")
    print(f"Status code: {e.status_code}")

Performance Tips

Optimize Your Queries

  1. Use appropriate geometries: Points for single locations, polygons for regions
  2. Limit date ranges: Shorter ranges = faster queries
  3. Set reasonable filters: Avoid overly restrictive criteria
  4. Use batch processing: For multiple regions
  5. Cache results: Store results for repeated analysis

Rate Limiting Best Practices

  • The system automatically handles rate limiting
  • Circuit breaker prevents cascading failures
  • Exponential backoff with jitter for retries
  • Monitor rate limit status with query.rate_limiter.get_current_rate_status()

Real-World Examples

Example 1: Agricultural Monitoring

# Monitor cropland around Po Valley, Italy
po_valley = {
    "type": "Polygon",
    "coordinates": [[
        [8.5, 45.0], [12.5, 45.0], [12.5, 46.0], [8.5, 46.0], [8.5, 45.0]
    ]]
}

# Search for growing season imagery
results = query.search_scenes(
    geometry=po_valley,
    start_date="2024-04-01",    # Spring planting
    end_date="2024-09-30",     # Harvest season
    cloud_cover_max=0.15,
    sun_elevation_min=35
)

print(f"Found {len(results['features'])} scenes for crop monitoring")

Example 2: Urban Development Tracking

# Track urban expansion around major city
city_buffer = {
    "type": "Point", 
    "coordinates": [9.19, 45.46]  # Milan center
}

# Monthly snapshots over one year
monthly_results = []
for month in range(1, 13):
    start_date = f"2024-{month:02d}-01"
    end_date = f"2024-{month:02d}-28"
    
    monthly_scenes = query.search_scenes(
        geometry=city_buffer,
        start_date=start_date,
        end_date=end_date,
        cloud_cover_max=0.2
    )
    monthly_results.append({
        "month": month,
        "scene_count": len(monthly_scenes['features'])
    })

print("Monthly scene availability:", monthly_results)

The Scene Discovery system provides the foundation for all satellite imagery analysis workflows in PlanetScope-py.