marijanic/map-annotation-tool
map-annotation-tool
An annotation-only browser application for reviewing prepared Docling figures and MapPool predictions, classifying map appearance, and georeferencing suitable figures. It runs locally through Gradio and online as a free Hugging Face Static Space. It does not run Docling or MapPool.
- Annotation app: <https://huggingface.co/spaces/marijanic/map-annotation-tool>
- Prepared figures and predictions: <https://huggingface.co/datasets/marijanic/map-annotation-tool-data>
- Pinned dataset revision:
ddf36b53ec5e8eeefcfc41d9923f97d5ec7ac62f
Contributor work is browser-local: annotations and unfinished GCPs are saved in IndexedDB, not on the Space filesystem. Export creates one conflict-safe JSON file for a manual GitHub pull request. data/annotations.jsonl remains the canonical dataset.
This deployment is a public preview for end-to-end review of the annotation workflow. The Dataset contains public BRGM document figures and MapPool prediction metadata; it does not distribute MapPool or OpenCLIP model weights.
Run locally with the copied images
Python 3.10 is recommended (the ZeroGPU runtime uses 3.10.13).
python3.10 -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e '.[test]'
python app.pyOpen <http://127.0.0.1:7860>. Local mode reads data/figures.jsonl, the read-only data/annotations.jsonl, and media paths relative to the repository (including the ignored copied media/ directory). Override them with DATA_MODE=local, FIGURE_MANIFEST_PATH, LOCAL_ANNOTATIONS_PATH, and LOCAL_MEDIA_ROOT. The app never edits canonical JSONL.
Leaflet is vendored and works offline. OpenStreetMap and Esri base-map tiles require browser internet access.
Prepared Hugging Face Dataset
The separate Dataset repository contains data already produced by Docling and MapPool:
figures.jsonl
media/
figures/...Every manifest row follows schema/figure-manifest.schema.json: portable media path, source PDF, dimensions, SHA-256, and either detector: null or MapPool label, margin, model identifier, backbone, and model checksum. Predictions are prioritization hints, never human labels.
The app shows the signed MapPool decision margin as a bounded, human-readable percentage. This is a logistic transformation of the margin's magnitude, not a calibrated probability. The raw margin remains available in the prediction tooltip and in figures.jsonl. An amber dashed prediction is unverified until a contributor explicitly chooses Map, Not a map, or Unsure.
python scripts/validate_figures.py figures.jsonl --media-root /path/to/dataset-rootConfigure the Static Space
Create a Static HTML Space and configure:
DATA_MODE=hf
HF_DATASET_ID=<hf-user>/map-annotation-tool-data
HF_DATASET_REVISION=<immutable-dataset-commit-sha>
FIGURE_MANIFEST_PATH=figures.jsonl
CANONICAL_ANNOTATIONS_URL=https://raw.githubusercontent.com/<github-user>/map-annotation-tool/main/data/annotations.jsonl
GITHUB_REPOSITORY_URL=https://github.com/<github-user>/map-annotation-toolThe public preview reads the 206 migrated ground-truth records from the pinned Dataset revision: CANONICAL_ANNOTATIONS_URL=https://huggingface.co/datasets/<user>/map-annotation-tool-data/resolve/<revision>/annotations.jsonl. Switch to the raw GitHub URL when that repository becomes the canonical collaborative source. HF_TOKEN is only needed when the Dataset is private.
The dataset revision must be an immutable commit. The static bootstrap reads Space variables from window.huggingface.variables, fetches the manifest and canonical annotations in the browser, and records their checksums in exports. No Python server or GPU is used.
MapPool provenance and citation
The prediction metadata was generated outside this repository with the classifier distributed by the MapPool inference Space: a polynomial support vector machine applied to L2-normalized OpenCLIP ViT-L/14 image embeddings. The model head is identified in the manifest as sraimund/MapPool:model.pkl, together with its SHA-256 checksum and the ViT-L-14-quickgelu/openai backbone identifier.
The classifier accompanies the MapPool dataset, which contains 75 million potential maps and captions derived from CommonPool. The upstream dataset card declares CC BY 4.0, while reminding users that copyright in the linked source images still applies. This annotation repository redistributes neither the MapPool model head nor the OpenCLIP weights.
When using MapPool or its predictions, cite the upstream dataset paper:
@inproceedings{Schnürer_MapPool_2024,
title = {MapPool - Bubbling up an extremely large corpus of maps for AI},
author = {Schnürer, Raimund},
year = {2024},
url = {https://infoscience.epfl.ch/handle/20.500.14299/240495}
}Contributor workflow
- Enter a contributor ID: either your GitHub handle or a stable alias made from letters, numbers, and hyphens. Press Enter or click Start.
- Select figures grouped by source PDF; optionally filter predictions or pending work.
- Review with the buttons or their displayed keyboard shortcuts.
- For a map, choose its type and add at least three well-spread GCPs before saving.
- Export the JSON. Either send it directly to the maintainer or add it to
submissions/<your-id>/<timestamp>.jsonin a pull request.
Use Backup to preserve unfinished GCP drafts in a separate browser-backup file; Import restores either a backup or a prior submission export. Reset all clears only the current handle's browser workspace after confirmation.
If GitHub main changed a record after a draft began, the draft is stale and cannot be exported. Discard it, inspect the latest annotation, and reapply the correction. Coordinate PDF assignments in GitHub issues to avoid duplicated work.
Maintainer workflow
map-annotation validate-submission submissions/alice/20260831T120000Z.json
map-annotation apply-submission submissions/alice/20260831T120000Z.json \
--annotations data/annotations.jsonl --out data/annotations.jsonl
map-annotation validate data/annotations.jsonl
git diff -- data/annotations.jsonl submissions/Application is atomic and deterministic. Additions require an absent base; corrections require the current row to match its base hash. Identical already-applied changes are accepted; conflicts are all reported and nothing is written.
See the annotation guide, contributor guide, submission contract, and maintainer review guide.
Checks for the user to run
pytest -q
map-annotation validate data/annotations.jsonl
python scripts/validate_figures.py data/figures.jsonl
# Optional browser coverage
python -m pip install -e '.[browser]'
python -m playwright install chromium
pytest -q -m browserThe manual acceptance checklist is in RELEASE.md.
