Bringing a Project Into Potato¶
You do not have to start over. Potato reads the export formats of most tools you might be leaving, and turns one into a runnable project in a single command.
python -m potato.importers --input <your-export> --output-dir my-project/
python potato/flask_server.py start my-project/config.yaml -p 8000
The importer writes a data file, a config.yaml with the right schema already
declared, and a README. Your existing annotations arrive as pre-annotations:
every annotator sees them as a starting point, and their corrections replace
them on save.
Supported formats¶
| Coming from | Format | Notes |
|---|---|---|
| brat | .ann + .txt |
Directory of file pairs. Discontinuous mentions survive; relations do not yet |
| doccano | JSONL | Sequence labelling and document classification |
| Prodigy | db-out JSONL |
Rejected tasks are dropped by default — see below |
| CoNLL corpora | CoNLL-2003, CoNLL-U | Column format or 10-column UD, NER from the tag column or MISC |
| NVivo, ATLAS.ti, MAXQDA, Quirkos, QDA Miner | REFI-QDA .qdpx |
Codebook hierarchy, codings and annotator identity |
| CVAT | XML 1.1 | |
| V7 / Darwin | JSON v2 | |
| Labelbox | NDJSON | |
| COCO | JSON | Polygons, RLE (compressed and not), crowd regions, keypoints |
| YOLO, Pascal VOC, LabelMe, VIA, KITTI, MOT, DAVIS, Cityscapes, Open Images, WebDataset, HuggingFace | various |
List them at any time:
python -m potato.importers --list-formats
The format is detected from the file, so --input-format is only needed when
detection cannot decide.
Text annotation¶
brat¶
Point at the directory; the importer pairs each .ann with its .txt.
python -m potato.importers --input ./my-corpus/ --output-dir potato-project/
Offsets are Unicode code points with an exclusive end. That is brat's convention and Potato's, so nothing is converted.
Discontinuous mentions (T1<TAB>LOC 0 3;17 21<TAB>New York) keep their extra
fragments. Relations (R) and events (E) are reported in the warnings rather
than imported: brat relations reference T ids that have to be resolved to
Potato span ids first, and getting that wrong would silently reattach a
relation to the wrong span.
doccano¶
python -m potato.importers --input export.jsonl --output-dir potato-project/
Span entries are read in all three shapes doccano has emitted across versions
([start, end, label], start_offset/end_offset, and start/end), so an
older export works. Document categories become their own multiselect scheme.
Prodigy¶
python -m potato.importers --input db-out.jsonl --output-dir potato-project/
Tasks answered reject or ignore are not imported by default. A rejection is
a human saying the annotations are wrong, and importing it as approved work
turns that into positive signal. Pass --prodigy-keep-rejected to bring them
in anyway. The answer field becomes a radio scheme, so the verdict survives
either way.
CoNLL¶
python -m potato.importers --input eng.train --output-dir potato-project/
CoNLL is token-based: it records what the tokens are and what tag each carries, never where they sat in a string. So the text is reconstructed before any character offset exists, and how faithfully depends on what the file kept:
- CoNLL-U with
# text =. Exact, because the sentence string is in the file. - CoNLL-U without it. Rebuilt from tokens.
SpaceAfter=NoinMISCis honoured. - CoNLL-2003. Tokens joined with single spaces. The format records no
spacing at all, so
"Dr. Smith"and"Dr. Smith"produce the same file.
The reconstruction is what gets stored, so the spans line up with what annotators see. The loss happens upstream, in what CoNLL records.
--conll-document-unit decides what counts as one annotation item: auto
(the default) follows -DOCSTART- and # newdoc markers and falls back to one
item per sentence, which is how most NER corpora are distributed.
Qualitative projects (REFI-QDA)¶
.qdpx is the interchange format NVivo, ATLAS.ti, MAXQDA, Quirkos and QDA
Miner all read and write.
python -m potato.importers --input project.qdpx --output-dir potato-project/
The codebook comes across with its hierarchy (each code keeps its parent), along with descriptions, colours, the codings themselves, and which annotator made each one.
Exporting back out:
python -m potato.export -c config.yaml -f qdpx -o ./export/
ATLAS.ti supports one level of subcode
REFI-QDA lets codes nest to any depth and so does Potato, but ATLAS.ti
flattens or drops anything past a single level on import — without telling
the researcher it happened. Export with flatten_subcodes to control that
yourself: every code is re-parented to the top level and renamed
Parent > Child > Grandchild, which loses the tree but keeps every code
legible.
Potato warns you when your codebook is deep enough for this to matter.
The offset trap¶
REFI-QDA 1.5 §10.2 says selections are "defined by the first and the last
character (Unicode codepoint)", which makes endPosition inclusive where
Potato's end is exclusive. Exporting tools have not all read that the same
way, and a file written with an exclusive end loses its last character on
import.
Potato measures both readings against the source text and uses the one that
fits. It warns when a file contradicts the spec, and
--qdpx-end-position inclusive|exclusive forces the reading if you need to.
Computer vision¶
# A single annotation file
python -m potato.importers --input instances_val2017.json \
--image-dir /data/val2017 --image-url-prefix /media \
--output-dir potato-project/
# A directory dataset (YOLO, KITTI, VOC, ...)
python -m potato.importers --input ./yolo-dataset/ --output-dir potato-project/
# Straight from the HuggingFace Hub
python -m potato.importers --hf-dataset cppe-5 --output-dir potato-project/
COCO files are read as-is: polygons, uncompressed RLE, compressed RLE strings and crowd regions all work without preprocessing. Category IDs survive the round trip, so an export keeps the original (often sparse) numbering.
Full detail, including per-format caveats, is in Import CLI and the CV Format Matrix.
Verifying an import¶
Imported annotations are pre-annotations, so an item nobody has opened exports as empty. That keeps machine output from being counted as human work, and it also makes an import hard to check end to end.
--seed-user writes the imported annotations as one annotator's saved work so
you can export immediately and diff:
python -m potato.importers --input ./corpus/ --output-dir p/ --seed-user check
python -m potato.export -c p/config.yaml -f conll_2003 -o p/export/
--seed-user fabricates an annotator
It exists to verify the round trip without a human opening every item. Never include a seeded user in agreement or adjudication analysis.
Known gaps¶
Each of these produces a warning on the import rather than a silence:
- brat relations and events. Reported in the warnings.
- Sub-token spans through CoNLL. A span covering
Parisinside the tokenParis.comes back as the whole token, since a file with sub-token spans is one no other CoNLL tool can read. - Whitespace, through CoNLL-2003. The format does not record it.
- Non-text QDA sources. Picture, PDF, audio and video sources in a
.qdpxare not imported yet; text sources are. - Uncoded selections in a
.qdpx. A highlight with no code attached has nothing to import. Counted in the warnings.
Related¶
- Import CLI — every flag
- Export Formats — going the other way
- Qualitative Data Analysis — what Potato does once a QDA project is in