Skip to content

来自 OBO 文件和 OLS4 的本体术语标签

标注者可以搜索 Cell Ontology、HPO、GO 或任何 OBO 本体,每次选择都会连同术语 id、名称、IRI 和版本一起保存,可离线使用,也可通过 OLS4 使用。

v2.13.0 新增

在 radio、multiselect、span 或 image_annotation 标注方案上加一个 label_source 块,就会多出一个针对某个本体的搜索框。标注者输入名称、同义词或 id 来选取术语,不必在固定的标签列表里翻找。每次选择都会连同术语的 id、名称、IRI 以及该术语所属的本体版本一起存储。生物审编人员用这项功能做基于 Cell Ontology 的细胞类型标注、基于人类表型本体(HPO)的表型标注和基于 MONDO 的疾病规范化,也用它为化学物质提及标注 ChEBI 术语、为切片上的组织区域标注 UBERON 术语、为基因产物标注 GO 术语。Potato 的一致性指标和导出都读取术语 id。一位标注者搜索了 "B cell",另一位直接输入了 id CL:0000236,两人的答案存储的是同一个 id,因此判为一致。

OBO 平面文件格式是 OBO Foundry 本体发布时使用的纯文本格式。Potato 读取 OBO 1.4。Ontology Lookup Service(OLS4)是 EMBL-EBI 面向生物医学本体的搜索服务和 API,机构也可以自行运行 OLS4 服务器。

  • 本地文件: 设置 service: file 时,Potato 在任务目录内的 OBO 1.4 文件中搜索。文件来源可以离线使用。
  • OLS4: 设置 service: ols4 时,Potato 在 OLS4 服务器上搜索。每次搜索都会把输入的文本发送到该服务器,除非标注方案设置了 allow_network: true,否则 Potato 拒绝启动。请求由 Potato 服务器发出,标注者的浏览器只与 Potato 通信。
  • 存储的记录: 每次选择都保存为 {obo_id, label, iri, ontology_version}。Potato 的一致性指标比较的是 obo_id。
  • 导出: 运行 python -m potato.export 并加上 --format ontology_terms,每个被选中的术语写为一行。
  • 无需额外安装: Potato 用自带的解析器读取 OBO,OLS4 调用使用 Potato 本来就依赖的 requests 包。

配置

下面的配置基于 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 个现行术语和 1 个已废弃术语,前缀为 SCL。这些 SCL id 不是 Cell Ontology 的 id。

对于图像标注方案,同样的块放在绘图工具旁边。下面这段局部配置为上面的配置添加第四个方案:

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 替换为一个方案,在 EBI 的 OLS4 服务器上搜索 Cell Ontology。ontology 的值是 OLS4 的本体 id,例如 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

要搜索自托管的 OLS4 服务器,请设置 base_url。allow_network 键是有意要求显式开启的。如果研究的搜索文本必须留在你自己的网络内,请使用 service: file。OLS4 块缺少 allow_network: true 时,Potato 拒绝启动。

选项

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使用 service: ols4 时必须为 true
base_urlols4https://www.ebi.ac.uk/ols4/apiOLS4 API 根地址
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 只根据 is_a 构建 root 子树。例如,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 本体在 .owl 文件之外还会发布 .obo 版本。请下载 .obo 版本,或用 ROBOT 转换 OWL 文件:

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 会通过同义词 "white blood cell" 找到 leukocyte,输入 SCL:0000099 会通过该术语的 alt_id 找到 T cell。

匹配的术语多于 max_results 时,一行状态信息会给出已显示的数量和总数,并提示标注者继续输入。搜索框下方有一行说明来源:文件来源显示本体和文件的版本,OLS4 来源显示本体名称加 "via OLS4"。

  • 键盘: 上下方向键在匹配项之间移动,Enter 选取高亮的匹配项,Escape 关闭列表,再按一次 Escape 清空搜索框。点击或轻触匹配项同样可以选取,每个匹配项的触控区域至少 44 像素高。
  • radio: 选取的术语显示为一个已选中的选项,选取另一个术语会替换前一个。
  • multiselect: 每个选取的术语显示为一个已勾选的复选框,取消勾选即移除该术语。
  • span: 选取的术语成为当前的片段标签,标注者随后高亮文本。高亮上方的标签块显示术语名称。
  • image_annotation: 选取的术语成为一个标签按钮和当前标签,标注者随后开始绘制。图像上已使用过的术语会在页面加载时显示为按钮。

Pocket Mode 不显示搜索框。因此,含有 label_source 方案的任务总是使用常规标注页面。常规页面在手机上同样可用。

网络访问与 OLS4 缓存

对于 service: file 方案,Potato 在任何时候都不发出网络请求。.obo 文件放进任务目录后,文件来源可以在气隙部署中运行。搜索在 Potato 服务器上针对解析后的文件进行。没有 allow_network: true 的 OLS4 方案无法访问网络,因为服务器会拒绝以该配置启动,并建议改用本地文件。

设置 service: ols4 和 allow_network: true 后,Potato 服务器把每次搜索连同 obsoletes=false 一起发送给 OLS4,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" 开头的消息,标注者仍可以回答固定标签。过去六小时内回答过的搜索由缓存提供。已经选取的术语仍然保存着,因为单选或多选答案保存的是完整记录,而片段和图像答案通过磁盘上的术语文件解析。如果 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 是由 id 构建的 OBO PURL;对于 OLS4,iri 是 OLS4 返回的 IRI。单选或多选答案保留选取那一刻的 ontology_version。.obo 文件被替换后,答案记录的仍然是标注者搜索时所用的版本。

方案存储方式
radio、multiselect每个术语一个标签。标签名是 obo_id,值是上面那条记录的 JSON 字符串
span片段的标签(name)是 obo_id
image_annotation每个形状的 label 是 obo_id,位于常规的 _data JSON 中

片段和形状只存储 id。导出时,service: file 从 .obo 文件中查找名称、IRI 和版本,service: ols4 则从 ontology_cache 下的 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 只对图像形状填写。当 id 不在当前文件或 OLS4 术语文件中时,known 列为 false。被新版本删除或标为废弃的术语会得到 false。导出会打印一条警告,给出这类行的数量。同一方案上的固定标签不会成为 ontology_terms 中的行。通用的 csv 导出把单选或多选术语写成名为 <schema>.<obo_id> 的列,列中是 JSON 记录;片段和形状则以 obo_id 作为标签。其他格式见导出格式。

一致性

Potato 的一致性指标比较的是 obo_id。radio 方案按名义标签计分(百分比一致率、Cohen's kappa、Fleiss' kappa 和 Krippendorff's alpha),multiselect 方案按术语 id 集合的 Jaccard 重叠和 MASI 加权 alpha 计分,span 方案按片段位置和 obo_id 计分,image_annotation 方案按每个形状的几何形状和术语 id 计分。两位标注者选取同一个术语即判为一致,即使两人的记录中 ontology_version 不同。父术语和子术语算作不同的标签,一致性计算不会沿本体层级给予部分得分。例如,T cell 和 CD4-positive T cell 计为不一致。如需考虑层级的比较,请导出 ontology_terms,并根据同一个 .obo 版本,用 obo_id 列自行计算相应指标。

示例

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

该示例包含四段简短的细胞描述、合成的 scl-sample.obo 本体,以及上面配置中的三个方案。

延伸阅读

实现细节请参阅源文档。