Термины онтологий как метки: файлы OBO и OLS4
Разметчики ищут термины в Cell Ontology, HPO, GO или любой онтологии OBO, и каждый выбор сохраняется с id термина, названием, IRI и релизом, без сети или через OLS4.
Новое в v2.13.0
Блок label_source в схеме radio, multiselect, span или image_annotation добавляет поле поиска по онтологии. Разметчик вводит название, синоним или id и выбирает термин, вместо того чтобы листать фиксированный список меток. Каждый выбор сохраняется вместе с id термина, его названием, IRI и релизом онтологии, из которого взят термин. Биокураторы применяют эту функцию для разметки типов клеток по Cell Ontology, разметки фенотипов по Human Phenotype Ontology (HPO) и нормализации заболеваний по MONDO, а также для пометки упоминаний химических веществ терминами ChEBI, участков тканей на слайде терминами UBERON и генных продуктов терминами GO. Метрики согласованности Potato и экспорт читают id термина. Разметчик, который искал «B cell», и разметчик, который ввёл id CL:0000236, согласны друг с другом, потому что оба ответа хранят один и тот же id.
Формат OBO flat file — это текстовый формат, в котором выходят релизы онтологий OBO Foundry. Potato читает OBO 1.4. Ontology Lookup Service (OLS4) — сервис поиска и API EMBL-EBI для биомедицинских онтологий, и организация может также запустить собственный сервер OLS4.
- Локальный файл: при
service: filePotato ищет по файлу OBO 1.4 внутри каталога задачи. Источник-файл работает без сети. - OLS4: при
service: ols4Potato ищет на сервере OLS4. Каждый поиск отправляет введённый текст на этот сервер, и Potato отказывается запускаться, если в схеме не заданоallow_network: true. Запрос делает сервер Potato, а браузер разметчика обращается только к Potato. - Сохраняемая запись: каждый выбор сохраняется как
{obo_id, label, iri, ontology_version}. Метрики согласованности Potato сравниваютobo_id. - Экспорт:
python -m potato.exportс--format ontology_termsзаписывает по одной строке на каждый выбранный термин. - Без дополнительной установки: Potato разбирает OBO собственным парсером, а запросы к OLS4 идут через пакет
requests, от которого Potato уже зависит.
Конфигурация
Конфигурация ниже задаёт три схемы над синтетической онтологией-образцом из примера Potato. Первая схема просит указать один основной тип клеток только через поле поиска, вторая предлагает фиксированный вариант None над полем поиска, а третья размечает спаны текста терминами одних лишь иммунных клеток:
annotation_task_name: "Cell types from an ontology"
task_dir: .
output_annotation_dir: annotation_output
data_files: [data/cell-descriptions.jsonl]
item_properties: {id_key: id, text_key: text}
user_config:
allow_all_users: true
annotation_schemes:
- annotation_type: radio
name: main_cell_type
description: "Which cell type does the description mainly talk about?"
labels: [] # search box only
label_requirement: {required: true}
label_source:
ontology: scl
service: file
file: ontologies/scl-sample.obo
- annotation_type: multiselect
name: other_cell_types
description: "Which other cell types are mentioned?"
labels: [None] # a fixed option above the search box
label_source:
ontology: scl
service: file
file: ontologies/scl-sample.obo
- annotation_type: span
name: immune_cell_mentions
description: "Highlight each immune cell mention and tag its type"
labels: []
label_source:
ontology: scl
service: file
file: ontologies/scl-sample.obo
root: SCL:0000001 # immune cell and its is_a descendantsС labels: [] или без ключа labels поле поиска остаётся единственным способом ответить. Если задан список, фиксированные метки показываются как обычно, а поле поиска располагается под ними. Фиксированная метка сохраняется как обычное название метки, и только термин, выбранный через поиск, сохраняется как термин онтологии. Поскольку в первой схеме задано required, Potato не даёт нажать Next, пока разметчик не выберет термин. В третьей схеме Potato ограничивает поиск термином иммунной клетки из root и всеми терминами, которые лежат под ним по is_a. Термин для нейрона в поиске спанов не появится никогда.
Potato не поставляет файлы онтологий. Скачайте нужный релиз .obo в каталог задачи и храните файл вместе с проектом. Релиз HPO лежит по адресу http://purl.obolibrary.org/obo/hp.obo, а релиз Cell Ontology — по адресу http://purl.obolibrary.org/obo/cl.obo. Файл scl-sample.obo из примера — вымышленная онтология с 19 действующими терминами, одним устаревшим термином и префиксом SCL. Идентификаторы SCL не являются идентификаторами Cell Ontology.
Для схемы разметки изображений тот же блок ставится рядом с инструментами рисования. Фрагмент ниже добавляет четвёртую схему к конфигурации выше:
- annotation_type: image_annotation
name: cells_in_image
description: "Box each cell and name its type"
tools: [bbox, polygon]
labels: []
label_source:
ontology: scl
service: file
file: ontologies/scl-sample.oboПоиск через OLS4 вместо файла
Фрагмент ниже заменяет annotation_schemes в конфигурации выше одной схемой, которая ищет по Cell Ontology на сервере OLS4 в EBI. Значение ontology — это id онтологии в OLS4, например cl, hp, go, mondo, chebi или uberon:
annotation_schemes:
- annotation_type: radio
name: cell_type
description: "Which cell type is described?"
labels: []
label_source:
ontology: cl
service: ols4
allow_network: true # required for ols4
root: CL:0000000 # optional, sent to OLS4 as childrenOf
timeout_s: 5Задайте base_url, чтобы искать на собственном сервере OLS4. Ключ allow_network — намеренное явное согласие на работу с сетью. Исследование, в котором текст поиска не должен покидать вашу сеть, использует service: file. Potato отказывается запускаться, если в блоке OLS4 нет allow_network: true.
Параметры
Все ключи, которые принимает label_source:
| Ключ | Сервис | По умолчанию | Значение |
|---|---|---|---|
ontology | оба | обязателен | Короткое название онтологии (cl, hp). Название показывается в подписи поля поиска, а для OLS4 это название в нижнем регистре служит id онтологии, который отправляется на сервер |
service | оба | обязателен | file или ols4 |
file | file | обязателен | Путь к файлу OBO 1.4 относительно task_dir и внутри task_dir. URL не принимается, потому что Potato не скачивает файлы онтологий |
max_file_mb | file | 300 | Файл больше заданного размера в мегабайтах отклоняется при запуске |
root | оба | нет | id термина, например CL:0000000. Предлагаются только этот термин и термины под ним по is_a |
max_results | оба | 20 | Число совпадений, показываемых за один поиск, целое число от 1 до 100 |
allow_network | ols4 | false | Должно быть true для service: ols4 |
base_url | ols4 | https://www.ebi.ac.uk/ols4/api | Корень API OLS4 |
timeout_s | ols4 | 5 | Сколько секунд ждать ответа OLS4, от 0,5 до 30 |
Сервер и python -m potato.validate_cli отклоняют конфигурацию и называют проблемный ключ, если выполняется любое из следующих условий:
label_sourceстоит в схеме типа, отличного отradio,multiselect,spanилиimage_annotation;serviceне равенfileилиols4, либо ключ относится к другому сервису (base_urlприfile);- ключ неизвестен;
- файл отсутствует, лежит вне
task_dir, большеmax_file_mb, является файлом OWL или не содержит терминов; rootне является термином файла или помечен как устаревший; либо- задан
service: ols4безallow_network: true.
Разбор файлов OBO
Potato читает теги заголовка data-version, ontology и default-namespace. В каждом блоке [Term] парсер берёт id, name, namespace, synonym, def, is_a, alt_id и is_obsolete, а также теги синонимов OBO 1.0, такие как exact_synonym, которые встречаются в старых файлах. Блоки [Typedef] пропускаются, а строки relationship: и intersection_of: не считаются рёбрами. Поэтому Potato строит поддерево root только по is_a. Например, поддерево UBERON содержит подклассы корневого термина и не содержит структур, связанных с ним только через part_of.
Сохраняемая ontology_version — это заголовок data-version файла, например scl/releases/2026-10-01 в образце. Файл без этого заголовка получает sha256: и первые 12 шестнадцатеричных цифр хеша файла. Файл разбирается один раз и хранится в памяти. Potato разбирает файл заново, когда меняется его размер или время изменения. Новый релиз, скопированный поверх старого файла, вступает в силу при следующем поиске без перезапуска.
Устаревшие термины исключаются из поиска и из всех поддеревьев, и Potato не переходит по тегу replaced_by к более новому термину. Поиск по alt_id находит основной термин, и Potato сохраняет основной id. Файлы OWL отклоняются с сообщением. Большинство онтологий OBO Foundry публикуют релиз .obo рядом с файлом .owl. Скачайте релиз .obo или преобразуйте файл OWL с помощью ROBOT:
robot convert --input cl.owl --output cl.oboДля большой онтологии, например NCBITaxon, возьмите slim-версию или файл-подмножество, увеличьте max_file_mb или ищите по онтологии через OLS4.
Поиск и выбор терминов
Разметчик вводит не меньше двух символов названия, синонима или id термина. Поиск по файлу ставит на первое место совпадение по id термина (CL:0000236, CL_0000236, alt_id или полный PURL), затем точное совпадение названия, название, которое начинается с введённого текста, и название, слова которого начинаются с каждого из введённых слов. Синонимы сравниваются теми же тремя способами, после чего идут совпадения с текстом в любом месте названия, а затем в любом месте синонима. Учитываются синонимы всех областей (EXACT, BROAD, NARROW и RELATED), и у совпадения, найденного через синоним, этот синоним показывается под названием термина. В результате также показываются id термина и первые 240 символов определения. В онтологии-образце ввод white blood находит leukocyte через синоним «white blood cell», а ввод SCL:0000099 находит T cell через alt_id этого термина.
Если совпадений больше, чем max_results, строка состояния сообщает, сколько совпадений показано и сколько найдено всего, и просит ввести больше текста. Строка под полем называет источник. Для источника-файла она показывает онтологию и версию файла, а для источника OLS4 — название онтологии и после него «via OLS4».
- Клавиатура: клавиши со стрелками вверх и вниз перемещают по совпадениям, Enter выбирает выделенное совпадение, Escape закрывает список, а повторное нажатие Escape очищает поле. Совпадение также выбирается щелчком или касанием, и каждое совпадение служит областью касания высотой не меньше 44 пикселей.
radio: выбранный термин появляется как отмеченный вариант, и выбор другого термина заменяет прежний.multiselect: каждый выбранный термин появляется как отмеченный флажок, и снятие флажка удаляет термин.span: выбранный термин становится активной меткой спана, после чего разметчик выделяет текст. Плашка над выделением показывает название термина.image_annotation: выбранный термин становится кнопкой метки и активной меткой, после чего разметчик рисует. Термины, уже использованные на изображении, появляются в виде кнопок при загрузке страницы.
Pocket Mode не показывает поле поиска. Поэтому задача со схемой, в которой есть label_source, всегда использует обычную страницу разметки. Обычная страница тоже работает на телефоне.
Доступ к сети и кеширование OLS4
Для схемы с service: file Potato не делает сетевых запросов ни на каком этапе. Когда файл .obo лежит в каталоге задачи, источник-файл работает в изолированном от сети развёртывании. Поиск выполняется по разобранному файлу на сервере Potato. Схема OLS4 без allow_network: true не может обратиться к сети, потому что с такой конфигурацией сервер отказывается запускаться и предлагает взамен локальный файл.
При service: ols4 и allow_network: true сервер Potato отправляет каждый поиск в OLS4 с obsoletes=false. В ответ OLS4 исключает устаревшие термины из результатов. Ответы на поиск кешируются в памяти сервера на шесть часов, не более 512 различных поисков, и строка релиза онтологии тоже кешируется на шесть часов. Браузер может повторно использовать ответ в течение пяти минут. Каждый термин, который возвращает OLS4, также записывается в <output_annotation_dir>/ontology_cache/<ontology>-ols4-terms.json. После перезагрузки Potato берёт из этого файла названия терминов для плашек спанов и кнопок меток на изображениях, и экспорт читает тот же файл.
Если OLS4 отвечает медленно или недоступен, поле поиска показывает «Search failed: OLS4 did not answer within 5 s.» или сообщение, которое начинается с «Search failed: OLS4 request failed», и разметчики по-прежнему могут выбирать фиксированные метки. Поиски, на которые был получен ответ за предыдущие шесть часов, обслуживаются из кеша. Уже выбранные термины остаются сохранёнными, потому что ответ radio или multiselect хранит запись целиком, а ответы для спанов и изображений разрешаются через файл терминов на диске. Если Potato не может получить релиз онтологии из OLS4, выборы сохраняются с пустой ontology_version до следующего запроса релиза, то есть не дольше шести часов. Для исследования, которое должно продолжаться при сбоях сети, скачайте файл .obo и переключитесь на service: file.
Сохраняемый ответ
Выбранный термин сохраняется в виде такой записи:
{"obo_id": "SCL:0000005", "label": "CD4-positive T cell",
"iri": "http://purl.obolibrary.org/obo/SCL_0000005",
"ontology_version": "scl/releases/2026-10-01"}Для источника-файла iri — это PURL OBO, построенный из id, а для OLS4 iri — это IRI, который возвращает OLS4. Ответ radio или multiselect хранит ontology_version на момент выбора. После замены файла .obo такой ответ по-прежнему называет релиз, в котором искал разметчик.
| Схема | Как сохраняется |
|---|---|
radio, multiselect | Одна метка на термин. Название метки — obo_id, а значение — запись выше в виде строки JSON |
span | Метка спана (name) — это obo_id |
image_annotation | label каждой фигуры — это obo_id внутри обычного JSON _data |
Спаны и фигуры хранят только id. Экспорт ищет название, IRI и версию в файле .obo для service: file и в файле терминов OLS4 в ontology_cache для service: ols4. Для спанов и фигур в файловом режиме экспорт записывает версию файла .obo на момент экспорта.
Экспорт
Формат ontology_terms записывает ontology_terms.csv и ontology_terms.jsonl, по одной строке на каждый выбранный термин:
python -m potato.export --config config.yaml --format ontology_terms --output out/Для одного разметчика на первом объекте из конфигурации выше ontology_terms.csv выглядит так:
user_id,instance_id,schema,annotation_type,ontology,obo_id,label,iri,ontology_version,start,end,text,shape_index,shape_type,known
ana,cells_01,main_cell_type,radio,scl,SCL:0000005,CD4-positive T cell,http://purl.obolibrary.org/obo/SCL_0000005,scl/releases/2026-10-01,,,,,,true
ana,cells_01,other_cell_types,multiselect,scl,SCL:0000011,macrophage,http://purl.obolibrary.org/obo/SCL_0000011,scl/releases/2026-10-01,,,,,,true
ana,cells_01,immune_cell_mentions,span,scl,SCL:0000011,macrophage,http://purl.obolibrary.org/obo/SCL_0000011,scl/releases/2026-10-01,128,150,large phagocytic cells,,,trueСтолбцы start, end и text заполняются для спанов, а shape_index и shape_type — для фигур на изображениях. Столбец known равен false, если id нет в текущем файле или в файле терминов OLS4. Термин, который более новый релиз удалил или пометил как устаревший, получает false. Экспорт выводит предупреждение с числом таких строк. Фиксированные метки той же схемы не попадают в строки ontology_terms. Общий экспорт csv записывает термин из radio или multiselect как столбец с именем <schema>.<obo_id>, в котором лежит запись JSON, а спаны и фигуры сохраняют obo_id в качестве метки. Остальные форматы описаны на странице Форматы экспорта.
Согласованность
Метрики согласованности Potato сравнивают obo_id. Схема radio оценивается как номинальная метка (процент согласия, каппа Коэна, каппа Флейса и альфа Криппендорфа), схема multiselect — по коэффициенту Жаккара и альфе с весами MASI над множествами id терминов, схема span — по позиции спана и obo_id, а схема image_annotation — по геометрии каждой фигуры и id термина. Два разметчика, выбравшие один и тот же термин, согласны, даже если в их записях разные значения ontology_version. Родительский и дочерний термины считаются разными метками, и код согласованности не даёт частичного балла за близость в иерархии онтологии. Например, T cell и CD4-positive T cell засчитываются как расхождение. Для сравнения с учётом иерархии экспортируйте ontology_terms и вычислите меру по столбцу obo_id с тем же релизом .obo.
Пример
python potato/flask_server.py start examples/classification/ontology-labels/config.yaml -p 8000В примере четыре коротких описания клеток, синтетическая онтология scl-sample.obo и три схемы из конфигурации выше.
Что почитать дальше
- Науки о жизни — Potato для биокурирования и разметки в науках о жизни
- Здравоохранение — Potato для клинической и биомедицинской разметки
- Связывание сущностей — привязка упоминания к записи в базе знаний, при которой метка спана остаётся фиксированной категорией
- Radio и Multiselect — схемы с одним и с несколькими вариантами ответа, которые принимают
label_source - Форматы экспорта — форматы экспорта Potato и команда экспорта
Подробности реализации приведены в исходной документации.