CLI Tools
Installation
The p4 CLI is installed automatically when you install p4tools:
pip install -e .This registers the p4 entry point (defined via console_scripts in pyproject.toml). The CLI depends on Typer and Rich.
Commands Overview
| Command | Description |
|---|---|
p4 setup |
Configure the Planet Four data root and database path |
p4 info |
Show current configuration and database summary |
p4 db-stats |
Show database statistics and top tiles/obsids by marking count |
p4 cluster-tile |
Cluster a single tile with optional inline plot |
p4 cluster-obsid |
Cluster all tiles for a HiRISE observation ID |
p4 produce |
Run full catalog production with parallel processing |
Parallel Execution Helper
run_parallel_with_progress is a general-purpose utility that wraps ProcessPoolExecutor with a Rich progress bar. It is used by the produce command to parallelize clustering and fnotching across hundreds of observation IDs.
run_parallel_with_progress
def run_parallel_with_progress(
func, # A *picklable* top-level function. Must accept a single positional
argument (the item) plus any keyword arguments from *func_kwargs*.
items, # Items to map over.
max_workers:int=4, # Number of parallel processes.
description:str='Processing', # Label shown in the progress bar.
func_kwargs:dict | None=None, # Extra keyword arguments forwarded to *func*.
): # Successful results in the original item order (skipping failures).
*Execute func(item, **func_kwargs) in parallel with a Rich progress bar.*
p4 setup
Configures the ~/.p4tools.ini file with the path to the data root directory where clustering results are stored. Optionally also stores the path to the raw Planet Four Parquet database.
p4 setup ~/planet4_data --db ~/planet4_data/p4_raw.parquetThis replaces the old interactive prompt that ran at import time when no config file existed.
setup
def setup(
data_root:str=<typer.models.ArgumentInfo object at 0x7f4846579820>,
db:Optional[str]=<typer.models.OptionInfo object at 0x7f4848267890>
):
Configure the Planet Four data root (and optionally the raw database path).
p4 info
Displays the current configuration in a Rich table: config file location, data root path, and all key/value pairs from the INI file.
p4 infoinfo
def info(
):
Show current configuration and database summary.
p4 db-stats
Shows summary statistics for a raw Planet Four database: total markings, unique tiles and obsids, breakdown by marking type, averages, and the top tiles/obsids ranked by number of markings. Useful for picking example tile IDs and obsids to test with cluster-tile / cluster-obsid.
p4 db-stats --db ~/planet4_data/p4_raw.parquet
p4 db-stats --db ~/planet4_data/p4_raw.parquet --top 20db_stats
def db_stats(
db:Optional[str]=<typer.models.OptionInfo object at 0x7f4846579010>,
top:int=<typer.models.OptionInfo object at 0x7f4846579430>
):
Show database statistics and top tiles/obsids by marking count.
p4 random-tile
Picks a random tile whose marking count is within 50% of the database average — i.e. a “typical” tile, useful for quick test runs.
p4 random-tile
p4 random-tile --db ~/planet4_data/p4_raw.parquetrandom_tile
def random_tile(
db:Optional[str]=<typer.models.OptionInfo object at 0x7f484657a4e0>
):
Print a random tile ID with a near-average marking count.
Terminal Image Display
_display_inline_image renders a PNG/JPEG inline in the terminal using the iTerm2 inline image protocol (also supported by WezTerm). Falls back to printing the file path on unsupported terminals. Used by cluster-tile to show plots without leaving the CLI.
p4 cluster-tile
Clusters citizen science markings on a single Planet Four tile using DBSCAN, then displays a summary table with fan/blotch cluster counts. With --plot (the default), it also renders a 3-panel figure showing the tile image, clustered fans, and clustered blotches.
# Cluster a single tile
p4 cluster-tile APF00003qk --db ~/planet4_data/p4_raw.parquet
# Without the inline plot
p4 cluster-tile APF00003qk --db ~/planet4_data/p4_raw.parquet --no-plotcluster_tile
def cluster_tile(
tile_id:str=<typer.models.ArgumentInfo object at 0x7f4846579d90>,
db:Optional[str]=<typer.models.OptionInfo object at 0x7f4846578cb0>,
savedir:Optional[str]=<typer.models.OptionInfo object at 0x7f484657af30>,
plot:bool=<typer.models.OptionInfo object at 0x7f484657bf20>
):
Cluster a single Planet Four tile and display the results.
p4 cluster-obsid
Clusters all tiles belonging to a HiRISE observation. This is the obsid-level equivalent of cluster-tile. Optionally runs fnotching (fan/blotch ambiguity resolution) after clustering.
# Cluster only
p4 cluster-obsid ESP_011296_0975 --db ~/planet4_data/p4_raw.parquet
# Cluster + fnotch
p4 cluster-obsid ESP_011296_0975 --db ~/planet4_data/p4_raw.parquet --fnotchcluster_obsid
def cluster_obsid(
obsid:str=<typer.models.ArgumentInfo object at 0x7f48465793d0>,
db:Optional[str]=<typer.models.OptionInfo object at 0x7f4846579e20>,
savedir:Optional[str]=<typer.models.OptionInfo object at 0x7f4846579a30>,
fnotch:bool=<typer.models.OptionInfo object at 0x7f4846579a60>
):
Cluster all tiles for a HiRISE observation ID.
p4 create-mosaic
Downloads HiRISE RED4/RED5 CCD images and runs the ISIS pipeline to create a RED45 mosaic cube for a single observation. Useful for testing mosaic creation before running full production.
p4 create-mosaic ESP_011350_0945
p4 create-mosaic ESP_011350_0945 --overwritecreate_mosaic
def create_mosaic(
obsid:str=<typer.models.ArgumentInfo object at 0x7f484657a390>,
overwrite:bool=<typer.models.OptionInfo object at 0x7f484657a3c0>
):
Create a RED45 mosaic cube for a single observation ID.
Picklable Wrappers
_cluster_single and _fnotch_single are top-level wrapper functions that can be pickled by ProcessPoolExecutor. They perform lazy imports to avoid serialization issues with module-level state.
p4 produce
The main catalog production command. Runs the full pipeline in four phases:
- Clustering — Parallel DBSCAN clustering of all observation IDs
- Fnotching — Parallel fan/blotch ambiguity resolution
- Post-processing — L1C summaries, tile/marking coordinates, metadata
- Marking IDs — Assigns unique identifiers to all catalog entries
Uses run_parallel_with_progress for phases 1 and 2, with configurable worker count. Supports --dry-run to preview the work without executing.
# Full production run
p4 produce v3.1 --db ~/planet4_data/p4_raw.parquet --workers 8
# Preview what would be done
p4 produce v3.1 --db ~/planet4_data/p4_raw.parquet --dry-runproduce
def produce(
version:str=<typer.models.ArgumentInfo object at 0x7f4846579d60>,
db:Optional[str]=<typer.models.OptionInfo object at 0x7f484657b7d0>,
workers:int=<typer.models.OptionInfo object at 0x7f484657aff0>,
dry_run:bool=<typer.models.OptionInfo object at 0x7f484657a3f0>
):
Run full catalog production with parallel processing and Rich progress.