Skip to content

Hierarchy

A category hierarchy for Open Images evaluation. Used by COCOeval to expand GT (and optionally DT) annotations up the hierarchy so that a "Dog" detection also counts as an "Animal" detection.

from hotcoco import COCO, COCOeval, Hierarchy

label_to_id = {cat["name"]: cat["id"] for cat in coco_gt.dataset["categories"]}
h = Hierarchy.from_file("bbox_labels_600_hierarchy.json", label_to_id=label_to_id)

ev = COCOeval(coco_gt, coco_dt, "bbox", oid_style=True, hierarchy=h)
ev.run()

See the Open Images evaluation guide for a full walkthrough.


Constructors

from_file

Hierarchy.from_file(path: str, label_to_id: dict[str, int] | None = None) -> Hierarchy

Parse an Open Images hierarchy JSON file (bbox_labels_600_hierarchy.json).

The JSON uses nested LabelName / Subcategory fields. label_to_id maps OID label strings (e.g. "/m/0jbk") to category IDs. Labels not present in label_to_id get virtual node IDs that won't appear in your dataset's category list.

Parameter Type Default Description
path str Path to the OID hierarchy JSON file
label_to_id dict | None None Maps OID label strings to category IDs; None assigns virtual IDs to all labels
label_to_id = {cat["name"]: cat["id"] for cat in coco_gt.dataset["categories"]}
h = Hierarchy.from_file("bbox_labels_600_hierarchy.json", label_to_id=label_to_id)

from_dict

Hierarchy.from_dict(
    tree_dict: dict,
    label_to_id: dict[str, int] | None = None,
) -> Hierarchy

Build a hierarchy from a Python dict in the OID JSON format (LabelName / Subcategory keys). Useful when you already have the hierarchy loaded as a dict.

import json

with open("bbox_labels_600_hierarchy.json") as f:
    tree = json.load(f)

h = Hierarchy.from_dict(tree, label_to_id=label_to_id)

from_parent_map

Hierarchy.from_parent_map(parent_map: dict[int, int]) -> Hierarchy

Build a hierarchy from an explicit {child_id: parent_id} mapping. Useful when constructing a hierarchy programmatically or from a database.

h = Hierarchy.from_parent_map({
    3: 1,   # cat 3's parent is cat 1
    4: 1,   # cat 4's parent is cat 1
    5: 2,   # cat 5's parent is cat 2
})

from_categories

Hierarchy.from_categories(categories: list[dict]) -> Hierarchy

Derive a hierarchy from supercategory fields in a category list. For each category with a supercategory value, looks up the matching category by name. If no matching category is found, a virtual node is created.

Handy for COCO-format datasets that already encode the hierarchy via supercategory:

h = Hierarchy.from_categories(coco_gt.dataset["categories"])

Self-referencing supercategories (where name == supercategory) are silently skipped.


Methods

ancestors

ancestors(cat_id: int) -> list[int]

Return the ancestor chain for a category, from self up to the root: [cat_id, parent_id, grandparent_id, ...].

Returns [cat_id] if the category has no parent, or [] if the category is unknown to the hierarchy.

h = Hierarchy.from_parent_map({3: 1, 1: 0})
h.ancestors(3)   # [3, 1, 0]
h.ancestors(1)   # [1, 0]
h.ancestors(0)   # [0]
h.ancestors(99)  # []  — unknown category

children

children(cat_id: int) -> list[int]

Return the direct children of a category, or [] if the category has no children.

h.children(1)   # [3, 4]
h.children(3)   # []

parent

parent(cat_id: int) -> int | None

Return the parent of a category, or None if it is a root node.

h.parent(3)   # 1
h.parent(0)   # None