CLI
The mapcv command follows the order you work in: init → plan → generate → info, plus split to redo splits, stats, card and verify to prepare a dataset for training and sharing, validate to check a config, doctor to check your installation and mcp to let an AI agent do all of this. The help blocks on this page are snapshots of mapcv --help from mapcv 0.2.0.
| Command | What it does | Touches the network |
|---|---|---|
mapcv init |
Write a config, guided or from a template | no |
mapcv plan |
Estimate tiles, patches, disk and memory | only to read a remote GeoTIFF’s header or fetch labels.osm |
mapcv generate |
Build or resume the dataset | yes |
mapcv info |
Summarize a dataset folder | no |
mapcv split |
Rewrite train/val/test lists from the manifest | no |
mapcv stats |
Per-band mean/std and class weights into stats.json |
no |
mapcv card |
Write a dataset card (README.md) |
no |
mapcv verify |
Check every file is there and unchanged | no |
mapcv export |
Hugging Face Parquet, WebDataset shards, Zarr or a TerraTorch data config | no |
mapcv validate |
Check a config’s fields | no |
mapcv cache |
Show or clear the on-disk tile cache | no |
mapcv mcp |
Serve mapcv to AI agents over MCP | only when an agent generates |
mapcv doctor |
Check the installation, extras, tile cache and network | a few small requests (none with --offline) |
Global options
Section titled “Global options” Usage: mapcv [OPTIONS] COMMAND [ARGS]...
Turn a region, imagery and labels into a ready-to-train segmentation, detection, instance segmentation, classification, change detection or regression dataset.
Start with mapcv init, check the cost with mapcv plan, then build with mapcv generate.
╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --version -V Show the mapcv version and exit. ││ --quiet -q Hide progress output; still show errors and ││ summaries. ││ --no-color Print without colours, as NO_COLOR=1 does. ││ --debug Show full tracebacks and mapcv's debug log (for ││ bug reports). ││ --debug-log FILE Also write the debug log to FILE. ││ --install-completion Install completion for the current shell. ││ --show-completion Show completion for the current shell, to copy ││ it or customize the installation. ││ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ 1. Build a dataset ─────────────────────────────────────────────────────────────────╮│ init Create a config: answer a few questions, or start from a template. ││ plan Estimate tiles, patches, disk and memory for a config without downloading. ││ generate Download imagery, rasterize labels and write patches, masks, manifest and ││ splits. │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ 2. Use a dataset ───────────────────────────────────────────────────────────────────╮│ info Summarize a generated dataset: source, shapes, class balance and splits. ││ split Re-split an existing dataset from its manifest; no images are read. ││ stats Per-band mean and std, class balance and class weights, written to ││ stats.json. ││ card Write a dataset card (README.md with Hugging Face metadata) for sharing. ││ verify Check that every file is present and intact (and SHA256SUMS, when there is ││ one). ││ export Export a dataset: Hugging Face Parquet, WebDataset shards, Zarr or a ││ TerraTorch config. │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ 3. Utilities ───────────────────────────────────────────────────────────────────────╮│ validate Check a config without reading labels or imagery (use plan for estimates). ││ cache Show or clear the on-disk cache of downloaded XYZ tiles. ││ mcp Run an MCP server over stdio so AI agents can build datasets with mapcv. ││ doctor Diagnose the installation, extras, tile cache and network. │╰──────────────────────────────────────────────────────────────────────────────────────╯| Option | Meaning |
|---|---|
--version, -V |
Print mapcv <version> and exit |
--quiet, -q |
Hide progress bars and progress messages. Put it before the command: mapcv -q generate mapcv.yaml |
--no-color |
Print without colours (bold and dim stay), as the NO_COLOR environment variable does. Output that goes to a file or a pipe has no colours anyway |
--debug |
After an error, also print the full traceback, and print mapcv’s debug log (imagery, chunks, tile cache, failed tiles and their causes, resume decisions) on stderr. For bug reports; tile URLs show only their host |
--debug-log FILE |
Write the debug log, tracebacks included, to FILE (works with or without --debug) |
--install-completion |
Install tab completion for the current shell |
--show-completion |
Print the completion script |
--help, -h |
Show help; works on every command |
--quiet hides the progress bars, the “Opening imagery” spinner and the resume message. Plans, warnings, errors and summaries (including the mapcv split summary line) are still printed.
Results (plans, summaries, tables) go to stdout; errors, with the next step to take, go to stderr, so mapcv plan mapcv.yaml > plan.txt still shows a failure on the terminal. Output that goes to a file or a pipe, or to a terminal with TERM=dumb, has no colours, spinners or redrawn lines: generate prints Opening imagery… and then a plain line per tenth of the chunks instead of a progress bar:
Reading imagery and writing patches: 0/40 chunks (0%), 0sReading imagery and writing patches: 4/40 chunks (10%), 31s…Reading imagery and writing patches: 40/40 chunks (100%), 5m 12sCounts read 1 patch and 1,234 patches, sizes 750.0 KB and 3.3 MB (1 KB = 1,000 bytes) and durations 45s, 3m 07s or 2h 05m. A command suggested in the output quotes a path with spaces, so it can be copied as it is.
mapcv init
Section titled “mapcv init” Usage: mapcv init [OPTIONS] [OUTPUT]
Create a config: answer a few questions, or start from a template.
╭─ Arguments ──────────────────────────────────────────────────────────────────────────╮│ OUTPUT <path> Where to write the config. [default: mapcv.yaml] │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --template -t NAME Write a ready-made example instead of ││ asking: xyz, sentinel2, geotiff, ││ earth-engine, detection, instance, ││ classification, change or regression. ││ --interactive --no-interactive Ask questions (default: when run in a ││ terminal without --template). ││ --force -f Overwrite an existing file. ││ --stdout Print the template instead of writing. ││ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Examples:
mapcv init guided, writes mapcv.yaml
mapcv init --template xyz --stdout print a template
mapcv init my.yaml -t sentinel2 a ready-made example
mapcv init gee.yaml -t earth-engine Sentinel-2 from Earth Engine
mapcv init boxes.yaml -t detection boxes for COCO and YOLO
mapcv init masks.yaml -t instance a mask per object (COCO RLE)
mapcv init tiles.yaml -t classification a label per patch (CSV)
mapcv init pairs.yaml -t change before/after pairs and change masks
mapcv init heights.yaml -t regression float targets from a raster-
Writes
mapcv.yamlin the current folder, or theoutputpath you give. -
Guided (default in an interactive terminal without
--template): four steps (imagery, area, labels, patches and output). For Google Earth Engine imagery (gee) it offers Sentinel-2 (10 m, with cloud filtering and masking), Landsat 8 (30 m), NAIP (about 0.6 m, United States) or any catalog image or collection, then asks for the dates, the cloud limit, your Cloud project and a zoom matched to the data’s resolution. The area can be a bounding boxwest,south,east,northor a vector file (.geojson/.json,.kml,.gpkg,.shp,.parquet/.geoparquet), whose polygon extent becomes the region (for a GeoPackage with several layers it asks which one); the wizard then offers to use the same file as labels and lists its attribute fields with example values (fields with more than 255 distinct values, such as IDs, are left out). With labels it also asks for the task:segmentation(the default),detection,instanceorclassification, for detection which box formats to write (COCO, YOLO or both), for instance whether to also write instance-ID PNGs, and for classification whether each patch gets one label or every class present. A label file ending in.tif/.tiffis taken as a label raster: the wizard shows its CRS, size and NoData, lists the values under the area with their share (from an overview or a sample of a large area), and writes aclassesblock that maps each value to an ID (the value itself when all are 1–254, else 1, 2, 3, … in value order;0is background) namedvalue_<n>, for you to rename and merge; the task is then segmentation (settask: classificationin the file to label patches from the raster instead). -
Template (
--template xyz,--template sentinel2,--template geotiff,--template earth-enginefor a cloud-free Sentinel-2 composite from Google Earth Engine,--template detectionfor boxes or--template instancefor masks from the quickstart buildings,--template classificationfor a label per patch,--template changefor before/after pairs with a change mask,--template regressionfor float targets from a raster of values, or whenever stdin/stdout is not a terminal): writes a fully commented example. Add--stdoutto print the template instead of writing a file. -
With GeoTIFF / COG imagery the wizard asks for the file’s path or URL right after the imagery choice, opens it, shows its CRS, size, band count, data type, NoData value and overviews, offers the whole file as the area (press Enter), and picks
pngornpyoutput to match the data (for a file with more than 3uint8bands it asks which bands to use). -
The wizard checks each answer where you give it and asks again: a bounding box that is not
west,south,east,north(a box that looks like latitude,longitude is shown with the longitude first), a zoom outside 1–22, an Earth Engine date that is notYYYY-MM-DD, a tile URL without{z},{x}and{y}, a Sentinel-2 product that is empty, and a label file that does not exist or has a suffix no label reader takes. After a bounding box it prints the centre (longitude, latitude), so a swapped pair shows. It does not ask for change detection or regression: those need before/after pairs or a raster of values, so start frommapcv init --template changeor--template regressionand edit the file. -
Without a terminal (piped input, or
--no-interactive) and without--template,initwrites thexyztemplate for its example region (Lahore) and says so, naming--template. -
An existing file is never overwritten without
--force(the guided mode asks first, before its questions):Terminal window $ mapcv init --template xyzmapcv.yaml already exists.Add --force to overwrite it, or name another file. -
Ctrl-C at a question stops with
Interrupted. Nothing was written.(exit code 130). When the input ends before the last question (answers piped in that run out), nothing is written either and mapcv suggests--template(exit code 1). -
The written file is validated. If it needs edits (for example, a custom tile URL entered in the wizard without
{x},{y}and{z}), mapcv still writes it and lists the fields to fix.
$ mapcv init # guided, writes mapcv.yaml$ mapcv init s2.yaml -t sentinel2 # Sentinel-2 template into s2.yaml$ mapcv init ortho.yaml -t geotiff # GeoTIFF/COG template into ortho.yaml$ mapcv init --template xyz --stdout # print the XYZ template$ mapcv init boxes.yaml -t detection # COCO + YOLO boxes from building footprints$ mapcv init masks.yaml -t instance # COCO RLE masks, one per building footprint$ mapcv init gee.yaml -t earth-engine # cloud-free Sentinel-2 composite from Earth Engine$ mapcv init tiles.yaml -t classification # one label, or a set of labels, per patch$ mapcv init change.yaml -t change # before/after pairs and a change mask$ mapcv init height.yaml -t regression # float targets from a raster of valuesmapcv plan
Section titled “mapcv plan” Usage: mapcv plan [OPTIONS] {config_path}
Estimate tiles, patches, disk and memory for a config without downloading.
╭─ Arguments ──────────────────────────────────────────────────────────────────────────╮│ * config_path <path> Path to the YAML config. [required] │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Example: mapcv plan mapcv.yamlLoads the config, parses the label file and estimates the run without downloading imagery. A file the config reads that does not exist (labels.path, region.path, a local imagery.path, …) stops it with exit code 1 and the key that names it; mapcv validate only warns about missing files. It uses the network only to read the header of a remote (https://, s3://) GeoTIFF or label raster, and to fetch labels.osm from Overpass. The panel shows the task (unless it is segmentation), the region size in km, ground resolution, raster size, tile count and download size (XYZ), label polygons (or, for a label raster, its CRS, size and pixel size, read from the header only) and the class map, the number of objects (detection and instance), patch count, output size, split settings and memory per chunk. Warnings follow the panel: skipped label features, a missing label file, labels (or a label raster) that don’t intersect the region, no patch fitting the region, a patch_size larger than the raster, or very many small files. When the plan holds no patch, or lists a problem that stops generate (a grid of more than 3,000,000 patches, sources that cannot be stacked), plan (like generate) ends with exit code 1 and no Looks right? line. The patch count is computed from the raster’s size, so plan answers at once and uses little memory however fine the stride or large the region.
Estimates use typical tile and file sizes. For Sentinel-2 the raster size is computed on the UTM grid of the region (with the zarr extra installed); the product’s exact grid is known only once it is opened, so the real size can differ by a few pixels.
mapcv generate
Section titled “mapcv generate” Usage: mapcv generate [OPTIONS] {config_path}
Download imagery, rasterize labels and write patches, masks, manifest and splits.
Re-running the same command resumes an interrupted run.
╭─ Arguments ──────────────────────────────────────────────────────────────────────────╮│ * config_path <path> Path to the YAML config. [required] │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --yes -y Don't ask before large downloads. ││ --dry-run Only show the plan, like mapcv plan. ││ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Examples:
mapcv generate mapcv.yaml
mapcv generate mapcv.yaml --yes (no prompt for large jobs, for CI)- Prints the same plan as
mapcv plan(and, like it, stops with exit code 1 when a file the config reads is missing or the plan holds no patch, or the grid is over the limit of 3,000,000 patches). With--dry-runit stops here. - Large jobs — more than 20,000 tiles, more than 5 GB of estimated download plus output, or more than 1,000,000 patches — ask
This is a large job. Start it?(default no; answering no exits with code 1). Without a terminal, generation refuses with exit code 2 unless you pass--yes. - Opens the imagery (with an “Opening imagery…” spinner), reprojects labels, checks that an existing
manifest.jsoninwriter.staging_diris compatible, then processes chunks with a progress bar (plain lines when the output is not a terminal; in a terminal narrower than 110 columns the bar drops its labels, then its ETA, then the bar itself, so no column is cut off), saving the manifest every few seconds and whenever the run stops (Ctrl-C, an error). - Writes split lists if the config has a
splitblock, then prints Dataset ready: patch count (and how many are new this run), shape and dtype, tiles fetched and failed, split sizes, elapsed time, the files and folders in the dataset (patch folders,manifest.json,splits/,patches.geojson, and the COCO, YOLO or label-table files of the task), the class balance, and next steps.
Warnings (skipped label features, labels outside the imagery, split leakage, more than half of the tiles failing) are printed once each, as ⚠ lines. Failures are reported as one Generation failed: … message without a traceback, followed by a hint to re-run; a refused resume is reported as Cannot resume: … instead. A folder that can’t be written and a full disk say so, with what to do:
Generation failed: permission denied: /data/ro/datasetMake that folder writable, or set writer.staging_dir to a folder you can write to. Then run the same command again: finished chunks are kept and the run resumes.Ctrl-C stops with Interrupted. Finished chunks are saved; run the same command again to resume. and exit code 130.
Resuming: run the same command again. Patches already in the manifest are skipped, and XYZ tiles are only fetched for chunks still to do. When everything is already written it prints Nothing left to do: all 77 patches are already written. Resuming refuses a folder made with different imagery, labels (including edits to the label file), sampler or writer settings, by mapcv 0.1, by mapcv 0.2 with sampler.mode: random, or by a newer mapcv; a 0.2 dataset resumes only with labels.ignore_index: null (see Large regions and resuming). A run with nothing new to do leaves the dataset as it is, split lists included, even if mapcv split changed them since; it warns when they differ from the config’s split settings. A run that writes no patch at all (every patch was dropped by sampler.max_empty_ratio or min_label_ratio) ends with No patches were written. and exit code 1, and leaves no manifest.json, split lists or patches.geojson: an empty dataset is no dataset, so verify, stats, split and export say that there is none instead of succeeding on nothing.
$ mapcv generate mapcv.yaml$ mapcv generate mapcv.yaml --dry-run$ mapcv -q generate mapcv.yaml --yes # CI: no prompts, no progress barsmapcv info
Section titled “mapcv info” Usage: mapcv info [OPTIONS] {staging_dir}
Summarize a generated dataset: source, shapes, class balance and splits.
╭─ Arguments ──────────────────────────────────────────────────────────────────────────╮│ * staging_dir <path> Dataset directory containing manifest.json. [required] │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Example: mapcv info dataset/Reads manifest.json (version 1, 2 or 3) and splits/ and prints the task, the source and product, bands, patch count and shape, CRS, the mask’s ignore value, how many patches are padded, split sizes, manifest version and per-class pixel shares. An older manifest is shown with its version, for example version 2 (mapcv 0.2; read as version 3), and is not modified.
$ mapcv info dataset╭─ dataset ────────────────────────────────────────────────────────────────────────────╮│ Task segmentation ││ Source xyz · esri_satellite ││ Bands red, green, blue ││ Patches 77 · 256×256×3 uint8 ││ CRS EPSG:3857 ││ Ignore mask value 255 marks pixels without imagery ││ Splits train 52 (68%) · val 8 (10%) · test 17 (22%) ││ Manifest version 3 │╰──────────────────────────────────────────────────────────────────────────────────────╯ class id pixels background 0 81.0% building 1 19.0%mapcv split
Section titled “mapcv split” Usage: mapcv split [OPTIONS] {staging_dir}
Re-split an existing dataset from its manifest; no images are read.
╭─ Arguments ──────────────────────────────────────────────────────────────────────────╮│ * staging_dir <path> Dataset directory containing manifest.json. [required] │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --test-ratio <float> Fraction of patches held out for testing. ││ [default: 0.2] ││ --val-ratio <float> Fraction of the remaining patches for validation. ││ [default: 0.1] ││ --labeled-ratios <float> Labeled fractions of train for semi-supervised ││ lists (repeatable). Default: 0.1 0.2 0.3. ││ --seed <int> Random seed. [default: 42] ││ --strategy <str> spatial (leakage-safe blocks) | stratified | ││ random | region (whole regions of an area of ││ interest). ││ [default: spatial] ││ --block-size <int> Spatial block size in pixels (default: 4 × patch ││ size). ││ --sample-limit <int> Split only a sample of this many patches (a small ││ benchmark from a large dataset); the other ││ patches are in no split. ││ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Examples:
mapcv split dataset/
mapcv split dataset/ --strategy spatial --block-size 2048 --test-ratio 0.15Rewrites STAGING_DIR/splits/ (including split.json, which records the settings and counts) from the manifest only, and with it the files that depend on the split: patches.geojson, the COCO files, YOLO lists and dataset.yaml (detection, instance) and the label tables (classification); images are never opened, so it takes seconds even for large datasets. Options mirror the split config block; the split settings in your YAML are not read.
| Option | Default | Notes |
|---|---|---|
--test-ratio |
0.2 |
Fraction of all patches for test |
--val-ratio |
0.1 |
Fraction of the rest for validation |
--labeled-ratios |
0.1 0.2 0.3 |
Repeat the option for several values: --labeled-ratios 0.05 --labeled-ratios 0.25 |
--seed |
42 |
|
--strategy |
spatial |
spatial, stratified, random or region (a dataset made with region.path) |
--block-size |
auto | Pixels; default 4 × patch size, smaller on small rasters |
--sample-limit |
none | Split a subsample of this many patches, for a small benchmark from a large dataset. The other patches are in no split; the command says how many |
$ mapcv split dataset --block-size 512 --labeled-ratios 0.05 --labeled-ratios 0.25✓ Splits written to dataset/splits: train 52 (68%) · val 8 (10%) · test 17 (22%)
$ mapcv split overlap --strategy random⚠ Patches overlap or repeat, so a 'random' split leaks pixels between train and test;use strategy 'spatial'.✓ Splits written to overlap/splits: train 196 (72%) · val 22 (8%) · test 55 (20%)Old splits/<percent>/ folders for ratios you no longer request are left in place. An option value that is out of range is a usage error (exit code 2), named after the option:
$ mapcv split dataset --test-ratio 2Usage: mapcv split [OPTIONS] {STAGING_DIR}Try 'mapcv split -h' for help.╭─ Error ──────────────────────────────────────────────────────────────────────╮│ Invalid value for '--test-ratio': Input should be less than or equal to 1 │╰──────────────────────────────────────────────────────────────────────────────╯mapcv stats
Section titled “mapcv stats” Usage: mapcv stats [OPTIONS] {staging_dir}
Per-band mean and std, class balance and class weights, written to stats.json.
╭─ Arguments ──────────────────────────────────────────────────────────────────────────╮│ * staging_dir <path> Dataset directory containing manifest.json. [required] │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --split <str> train, val, test or all: the patches to count. ││ [default: train] ││ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Examples:
mapcv stats dataset/ train split (all patches without splits)
mapcv stats dataset/ --split allReads every patch of a split and writes STAGING_DIR/stats.json:
- Per source and band:
mean,std(population),min,maxandpixels(how many were counted). Feedmeanandstdto your normalisation, as TerraTorch’smeans/stdsortorchvision.transforms.Normalize. - Class balance: pixel counts, frequencies and median-frequency class weights (Eigen & Fergus: the median of the class frequencies divided by each class’s frequency, where a class’s frequency is its pixels over the pixels of the patches it appears in) for
segmentationandchange; object counts per class fordetectionandinstance; patch counts per label forclassification. - Targets (
regression): mean, std, min and max of the target values.
Only the train split is counted by default, so validation and test pixels don’t leak into the normalisation; --split all counts every patch, and a dataset without split lists is always counted whole. A pixel counts when the mask doesn’t mark it as ignored (ignore_index: no imagery or no label); without a mask (image-only datasets), when it is finite and not the source’s NoData value on every band (all zero for XYZ tiles, where failed tiles are black). The statistics are accumulated per band in float64 with Welford/Chan merging, so they stay exact over billions of pixels.
$ mapcv stats dataset source band mean std min max image b1 124.991 71.8234 1 249 image b2 124.604 71.8503 1 249 image b3 125.002 71.7828 1 249Class weights (median frequency): background 0.769, a 1.43✓ 36 patches of the train split → dataset/stats.jsonCounting an unfinished dataset (generate stopped before it finished: its manifest’s complete is false) prints a ⚠ line saying so, since the numbers cover only the patches written so far; run mapcv generate again with the dataset’s config to finish it first.
stats.json is written on request, not by generate: reading every patch back costs about as long as writing it, and generate’s output stays the same as before. Run it again after mapcv split.
mapcv card
Section titled “mapcv card” Usage: mapcv card [OPTIONS] {staging_dir}
Write a dataset card (README.md with Hugging Face metadata) for sharing.
╭─ Arguments ──────────────────────────────────────────────────────────────────────────╮│ * staging_dir <path> Dataset directory containing manifest.json. [required] │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --force Replace an existing README.md. ││ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Example: mapcv card dataset/Writes STAGING_DIR/README.md, a dataset card with Hugging Face dataset-card YAML metadata (license, task_categories, tags, size_categories), so the folder can be pushed to the Hub or archived as is. The card describes the imagery (type, product, CRS, ground sampling distance, bands and data type), the classes, the split sizes, the normalisation values (when stats.json exists, so run mapcv stats first), the files, the provenance (mapcv and manifest version, label file SHA-256, imagery fingerprints) and the provider’s credit line for built-in sources.
The licence is other until you change it: mapcv can’t know what the imagery provider’s terms allow (see Providers & licensing). An existing README.md is kept unless you pass --force. A dataset that generate did not finish gets a ⚠ line, because the card describes only the patches written so far.
mapcv verify
Section titled “mapcv verify” Usage: mapcv verify [OPTIONS] {STAGING_DIR}
Check that every file is present and intact (and SHA256SUMS, when there is one).
╭─ Arguments ──────────────────────────────────────────────────────────────────────────╮│ * STAGING_DIR <path> Dataset directory containing manifest.json. [required] │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --deep Also decode every image and mask and check them against ││ the manifest. ││ --write-checksums Write SHA256SUMS after a successful check. ││ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Examples:
mapcv verify dataset/
mapcv verify dataset/ --deep --write-checksumsChecks a dataset against its manifest: generate finished it (the manifest’s complete; an interrupted dataset fails with the advice to run mapcv generate again), every listed file exists, is not empty and is not cut short (a PNG ends with its end chunk, a JPEG with its end marker, an NPY file holds the bytes its header promises, a TIFF starts with a TIFF header), and the split lists name only patches of the manifest, share none and match splits/split.json (which an interrupted mapcv split leaves out). --deep also decodes every image and compares its shape with the source’s patch_shape, and decodes every mask: its size must be the patch size and its pixel count per class the one the manifest records, so a mask with an unknown value or another class is found. Files in the patch folders that the manifest doesn’t list (left by an interrupted run, or added by hand) are reported as a note, not a failure.
--write-checksums writes SHA256SUMS (the sha256sum format) over every file in the dataset folder (patches, manifest.json, splits/, annotations and label tables, patches.geojson, …), after a successful check, or when the only differences are files that mapcv split, stats and card rewrite (it says so and records their new hashes). A missing or changed patch still blocks it. When SHA256SUMS exists, verify checks every hash, so a copied, uploaded or downloaded dataset can be proven complete and unchanged; sha256sum -c SHA256SUMS in the folder checks the same thing without mapcv.
$ mapcv verify dataset --write-checksums✓ 48 patches, 96 files present.✓ SHA256SUMS written to dataset/SHA256SUMS
$ mapcv verify copy-of-dataset✗ Masks/patch_0000012.png does not match its SHA256SUMS hash1 problem found.Copy the dataset again from where it came from, or generate it into a new folder.Exit code 1 when anything is missing, empty, cut short, unreadable (--deep) or changed. Files the manifest doesn’t list are ⚠ lines and don’t fail the check.
mapcv split, mapcv stats and mapcv card rewrite files that SHA256SUMS covers (the split lists and the outputs that follow them, stats.json, README.md). verify names such a file as changed since SHA256SUMS was written (mapcv split, stats and card rewrite it); when they are the only changes, run mapcv verify --write-checksums to record the new hashes instead of copying the dataset again.
mapcv export
Section titled “mapcv export” Usage: mapcv export [OPTIONS] {staging_dir}
Export a dataset: Hugging Face Parquet, WebDataset shards, Zarr or a TerraTorch config.
╭─ Arguments ──────────────────────────────────────────────────────────────────────────╮│ * staging_dir <path> Dataset directory containing manifest.json. [required] │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ * --format -f <str> hf-parquet (Hugging Face), webdataset ││ (tar shards), zarr (one store) or ││ terratorch (a data config). ││ [required] ││ --out -o <path> hf-parquet, webdataset, zarr: a new ││ folder (required). terratorch: the YAML ││ file (default ││ STAGING_DIR/terratorch.yaml). ││ --shard-mb <int range> [x>=1] webdataset: largest shard size in MB. ││ [default: 1000] ││ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Examples:
mapcv export dataset/ --format hf-parquet --out dataset-hf/
mapcv export dataset/ --format terratorch writes dataset/terratorch.yamlWrites a dataset in the form another tool reads; the dataset itself is not changed. A dataset that generate did not finish (its manifest’s complete is false) is refused with the advice to run mapcv generate again with its config: an export would leave out patches and split members. (Manifests from mapcv 0.2 and earlier have no such flag and are exported.)
OUT of hf-parquet, webdataset and zarr must be new or empty, or hold an earlier export of the same format, which is replaced whole (no split file or shard of it is left next to the new ones); a folder with other files is refused, and an export that fails part way removes what it wrote.
hf-parquet(needspip install "mapcv[export]"):OUT/data/<split>-00000-of-00001.parquetfor each split (allwithout split lists) andOUT/README.md, a dataset card whose metadata names the split files, sodatasets.load_dataset("OUT")and the Hugging Face Hub read it as is. Each patch file is a{bytes, path}column holding the file exactly as written (PNG and JPEG columns are typed as images; NPY and GeoTIFF columns hold the bytes, fornp.load(io.BytesIO(...))or rasterio’sMemoryFile), next toname,row,col,crs,transformand, for classification,labels.webdataset:OUT/<split>-000000.tar, … of at most--shard-mbMB (default 1000), andOUT/shards.jsonlisting each split’s shards and sample counts. A sample is one patch:<name>.png(or.jpg,.npy,.tif: the image file as written),<name>.mask.<ext>,<name>.<source>.<ext>for further sources, and<name>.json(row,col,transform,crs,split, the manifestsummary, and for detection and instance segmentation the COCOannotations). Samples follow the split lists’ order; the tars are byte-for-byte reproducible. Stream them with the webdataset library without unpacking.zarr(thezarrextra):OUTis a Zarr group withimages/<source>(N, C, H, W),masks(N, H, W),split(0train,1val,2test,255none),rowandcol, one patch per chunk, plus copies ofmanifest.json,splits/and the COCO files.MapcvDatasetreads it like the dataset folder:MapcvDataset("dataset.zarr", split="train"). The store is in the zarr 2 format and needs zarr 2.x (what the extra installs); with zarr 3 the export stops with a message before writing anything.
All three pack the dataset into a few files for copying, object storage and fast reading; the dataset folder is unchanged and every other command keeps working on it. To change splits, run mapcv split on the folder and export again.
terratorch: thedata:section of a TerraTorch training config,GenericNonGeoSegmentationDataModule(orGenericNonGeoPixelwiseRegressionDataModule) with the dataset’sImages/andMasks/folders, its split lists,num_classes, and the bandmeansandstdsof the train split (fromstats.json, or computed). It covers single-source segmentation and regression datasets written astiforpng(TerraTorch reads files with GDAL, which cannot read NPY). A comment says whichignore_indexthe task needs:-1for GeoTIFF masks, whose ignore value TerraTorch reads as missing, and255for PNG masks.
$ mapcv export dataset --format terratorch✓ TerraTorch data config written to dataset/terratorch.yaml; paste it into your training config.mapcv validate
Section titled “mapcv validate” Usage: mapcv validate [OPTIONS] {config_path}
Check a config without reading labels or imagery (use plan for estimates).
╭─ Arguments ──────────────────────────────────────────────────────────────────────────╮│ * config_path <path> Path to the YAML config. [required] │╰──────────────────────────────────────────────────────────────────────────────────────╯╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Example: mapcv validate mapcv.yamlParses the YAML and runs every field check, prints the resolved settings, and warns about a local file the config reads that does not exist (labels.path, a local imagery.path, …). A path that names a folder, a named pipe or a device instead of an ordinary file stops it with exit code 1, as plan and generate do. It reads neither the label file nor any imagery; use mapcv plan for that.
$ mapcv validate bad.yamlConfig error in bad.yaml: • region: region.west must be less than region.east • imagery.source: the built-in 'google_satellite' source was removed in mapcv 0.2.0: Google does not permit downloading its imagery for datasets (see MIGRATION.md and PROVIDERS.md) • labels.path: labels.path must be a .geojson, .json, .kml, .gpkg, .shp, .parquet or .geoparquet file, got 'buildings.kmz' (a KMZ is a zipped KML: unzip it and use the .kml inside)Fix the fields above, or start from a working config with mapcv init.
$ mapcv validate unknown.yamlConfig error in unknown.yaml: • imagery: imagery: set 'source' or 'url_template', not both • sampler.stide: Extra inputs are not permittedFix the fields above, or start from a working config with mapcv init.
$ mapcv validate broken.yamlConfig error in broken.yaml: not valid YAML at line 4, column 3 (expected <block end>, but found'-').Check the indentation, colons and brackets there.mapcv cache
Section titled “mapcv cache” Usage: mapcv cache [OPTIONS]
Show or clear the on-disk cache of downloaded XYZ tiles.
╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --clear Delete the cached tiles. ││ --expired With --clear: delete only the tiles that have expired. ││ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Examples:
mapcv cache where it is and how big
mapcv cache --clear --expired delete only expired tilesShows where the tile cache is, how many tiles it holds, their size and how many have expired. --clear deletes every cached tile; --clear --expired deletes only the expired ones. Only .tile files mapcv wrote are touched.
$ mapcv cacheTile cache: /home/me/.cache/mapcv/tiles 1,284 tiles, 31.6 MB, 96 expiredSet MAPCV_CACHE_DIR to move it, or imagery.cache: false to skip it.
$ mapcv cache --clear --expired✓ Deleted 96 expired cached tiles from /home/me/.cache/mapcv/tilesmapcv mcp
Section titled “mapcv mcp” Usage: mapcv mcp [OPTIONS]
Run an MCP server over stdio so AI agents can build datasets with mapcv.
Needs pip install "mapcv[mcp]". Without --allow-write the server can only read, validate and plan.
╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --root <path> The only folder the server may read or write ││ (default: the current folder). ││ [default: .] ││ --allow-write Also offer the tools that write: write_config, ││ generate and split. ││ [env var: MAPCV_MCP_ALLOW_WRITE] ││ --allow-local-urls Let the tools connect to this machine and ││ private networks (a local tile or GeoTIFF ││ server). Without it they reach public addresses ││ only. ││ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Examples:
mapcv mcp read-only, in this folder
mapcv mcp --root ~/work --allow-write may write datasets under ~/work
mapcv mcp --allow-local-urls may also read a tile or GeoTIFF server on this machine or a private networkRuns an MCP server over stdio so an AI agent can inspect labels, validate a config, plan, generate and inspect a dataset. It needs the mcp extra (pip install "mapcv[mcp]"); without it the command prints the install command and exits with code 1.
- Read-only by default. Without
--allow-writethe toolswrite_config,generateandsplitdo not exist on the server; with it they are offered (andstatsandverifymay writestats.jsonandSHA256SUMS). The environment variableMAPCV_MCP_ALLOW_WRITE=truedoes the same, for clients that configure servers through the environment. --rootis the only folder the server reads or writes (default: the current folder). Paths outside it, including the ones a config resolves to, are refused.- Public addresses only by default. The tools do not connect to this machine or a private network: a URL in a config that names one (
localhost,127.0.0.1,10.x,169.254.169.254, …), a host name that resolves to one, and a redirect to one are refused with the same message, whatever is listening there.--allow-local-urlslifts this, for a tile or GeoTIFF server you run yourself. - Progress bars are silenced, because stdout carries the protocol; logs go to stderr.
Install snippets for Claude Code, Claude Desktop, Cursor and VS Code, the tool list and the safety model are in Use mapcv with AI agents.
mapcv doctor
Section titled “mapcv doctor” Usage: mapcv doctor [OPTIONS]
Diagnose the installation, extras, tile cache and network.
Takes a few seconds, for you and for bug reports. Changes nothing (it writes and deletes one small probe file in the tile cache folder) and prints no secrets. Exits with 1 if a check fails, such as a broken Rust extension or a tile cache folder that can't be written; a warning does not fail the run.
╭─ Options ────────────────────────────────────────────────────────────────────────────╮│ --json Print the checks as JSON (no colour), for bug reports and ││ scripts. ││ --offline Skip the network checks (no request leaves this machine). ││ --help -h Show this message and exit. │╰──────────────────────────────────────────────────────────────────────────────────────╯
Examples:
mapcv doctor check this installation
mapcv doctor --offline skip the network checks
mapcv doctor --json for bug reports and scriptsDiagnoses an installation in a few seconds. Run it first when something does not work, and paste its output into a bug report. It reads, and changes nothing but one small probe file in the tile cache folder, which it deletes at once. It never prints a secret: a credentials file is looked for but never opened, and a proxy is named but its value is not shown.
| Section | What it checks |
|---|---|
| mapcv | mapcv version, Python version and implementation, the interpreter, the operating system and CPU (with the C library on Linux), and where mapcv is installed |
| Core | The Rust extension loads and is the same version as the Python package; the version of each core dependency |
| Extras | Whether zarr (Sentinel-2 EOPF), gee (Earth Engine, and whether credentials exist), parquet / export (pyarrow; the hint names mapcv[parquet] for GeoParquet labels and mapcv[export] for the Hugging Face export) and mcp (must be 2.x) are installed. A missing extra is info with the pip install "mapcv[…]" command, not a problem |
| Tile cache | The cache folder (see MAPCV_CACHE_DIR), whether it can be written, and how many tiles it holds |
| Terminal | Output encoding, whether output is a terminal, colour (NO_COLOR, --no-color) and width |
| Network | Whether the Esri World Imagery tile service, the EOPF STAC catalog, the Earth Search STAC catalog and (with earthengine-api installed) Earth Engine answer, with the HTTP status and the time they took; and which proxy variables are set. Each request times out after 5 seconds and they run at the same time |
Each line is ok, warn, FAIL or info, with a hint under it saying what to do next. The word is printed, so the report reads the same without colour. An unreachable service is a warn, not a failure: you may not use that provider. The command exits with 1 if a check fails (the Rust extension is missing or the wrong version, a core dependency is missing, or the tile cache folder can’t be written), and with 0 otherwise, warnings included.
| Option | Meaning |
|---|---|
--offline |
Skip the network checks. No request leaves your machine |
--json |
Print the checks as JSON instead of the table, with no colour and \n line endings, for bug reports and scripts |
--json prints one object with ok (false if any check failed), offline and checks, a list of records with the keys section, name, status (ok, warn, fail or info), detail and hint (null when there is nothing to do).
$ mapcv doctormapcvok mapcv 0.3.0ok Python 3.12.13 (CPython)info Interpreter ~/mapcv-env/bin/python3info System Linux 7.0.0-34-generic x86_64 (glibc 2.43)info Location ~/mapcv-env/lib/python3.12/site-packages/mapcv
Coreok Rust extension loaded, version 0.3.0ok pillow 12.3.0ok numpy 2.4.4ok shapely 2.1.2ok pydantic 2.13.5ok typer 0.27.2ok rich 15.0.0ok pyyaml 6.0.3ok typing-extensions 4.16.0ok pyproj 3.7.2ok pyshp 3.1.6
Extrasok zarr xarray-eopf 0.2.9, zarr 2.18.7ok gee earthengine-api 1.7.47ok Earth Engine credentials found: ~/.config/gcloud/application_default_credentials .jsonok parquet / export pyarrow 25.0.1ok mcp mcp 2.3.0
Tile cacheok Folder ~/.cache/mapcv/tiles, writableinfo Contents 8 tiles, 136.1 KB
Terminalok Encoding utf-8info Output not a terminal (piped or redirected)info Colour off (NO_COLOR is set)info Width 80 columns
Networkinfo Proxy noneok Esri World Imagery tiles HTTP 200 in 1,459 msok EOPF STAC catalog HTTP 200 in 682 msok Earth Search STAC HTTP 200 in 1,141 msok Earth Engine HTTP 404 in 645 ms (it answered)
All checks passed.Paste this output, or the output of mapcv doctor --json, into a bug report.Paths under your home folder are shown with ~. The example above comes from a real run, with the two install paths shortened.
Exit codes
Section titled “Exit codes”| Code | When |
|---|---|
0 |
Success (also generate --dry-run, and init when the written file still needs edits) |
1 |
Config not found or invalid, a file the config reads is missing (plan, generate), generation failed or wrote no patch, resume refused, dataset or manifest not found, a file that can’t be read or written, file exists without --force, mapcv verify found a problem, mapcv doctor found a failed check, a declined large-job prompt, or the input ended during mapcv init’s questions |
2 |
Invalid command-line usage: an unknown command or option, a missing argument, or an option value that is not allowed (stats --split nope, export --format coco, export without the --out its format needs, cache --expired without --clear, a split ratio out of range, mcp --root that is not a folder). Also a large job without a terminal and without --yes. mapcv with no command prints the help and exits with 2 too |
130 |
Interrupted with Ctrl-C (any command; generate keeps the finished chunks) |
Errors are printed on stderr, everything else on stdout.