Skip to content

Термины онтологий как метки: файлы 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: file Potato ищет по файлу OBO 1.4 внутри каталога задачи. Источник-файл работает без сети.
  • OLS4: при service: ols4 Potato ищет на сервере 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 над полем поиска, а третья размечает спаны текста терминами одних лишь иммунных клеток:

yaml
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.

Для схемы разметки изображений тот же блок ставится рядом с инструментами рисования. Фрагмент ниже добавляет четвёртую схему к конфигурации выше:

yaml
  - 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:

yaml
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
filefileобязателенПуть к файлу OBO 1.4 относительно task_dir и внутри task_dir. URL не принимается, потому что Potato не скачивает файлы онтологий
max_file_mbfile300Файл больше заданного размера в мегабайтах отклоняется при запуске
rootобанетid термина, например CL:0000000. Предлагаются только этот термин и термины под ним по is_a
max_resultsоба20Число совпадений, показываемых за один поиск, целое число от 1 до 100
allow_networkols4falseДолжно быть true для service: ols4
base_urlols4https://www.ebi.ac.uk/ols4/apiКорень API OLS4
timeout_sols45Сколько секунд ждать ответа 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:

bash
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.

Сохраняемый ответ

Выбранный термин сохраняется в виде такой записи:

json
{"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_annotationlabel каждой фигуры — это obo_id внутри обычного JSON _data

Спаны и фигуры хранят только id. Экспорт ищет название, IRI и версию в файле .obo для service: file и в файле терминов OLS4 в ontology_cache для service: ols4. Для спанов и фигур в файловом режиме экспорт записывает версию файла .obo на момент экспорта.

Экспорт

Формат ontology_terms записывает ontology_terms.csv и ontology_terms.jsonl, по одной строке на каждый выбранный термин:

bash
python -m potato.export --config config.yaml --format ontology_terms --output out/

Для одного разметчика на первом объекте из конфигурации выше ontology_terms.csv выглядит так:

text
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.

Пример

bash
python potato/flask_server.py start examples/classification/ontology-labels/config.yaml -p 8000

В примере четыре коротких описания клеток, синтетическая онтология scl-sample.obo и три схемы из конфигурации выше.

Что почитать дальше

  • Науки о жизни — Potato для биокурирования и разметки в науках о жизни
  • Здравоохранение — Potato для клинической и биомедицинской разметки
  • Связывание сущностей — привязка упоминания к записи в базе знаний, при которой метка спана остаётся фиксированной категорией
  • Radio и Multiselect — схемы с одним и с несколькими вариантами ответа, которые принимают label_source
  • Форматы экспорта — форматы экспорта Potato и команда экспорта

Подробности реализации приведены в исходной документации.