Specification¶
Specification for creating, validating, and publishing versioned HiTOP factorization models.
Status · Maintained specification Source · docs/factorizations.md Applies to · factorizations/ · schema/factorization-hierarchy.schema.jsonPurpose¶
The core ontology (ontology/hitop.rdf) is a kit of parts: it defines stable, reusable concept classes (Superspectra, Spectra, Subfactors, Components, Traits) and the shared vocabulary used to compose them into a hierarchy (hitop:hasTier, hitop:hasLevel — see Vocabulary).
A factorization is a concrete, versioned composition of those parts into one particular HiTOP structure. It is maintained as a single, human-readable YAML document, which a generator script (scripts/generate_factorization_ontology.py) mechanically compiles into a formal RDF ontology that references only the stable core classes.
Principles¶
- A factorization MUST NOT define new concepts. It may only reference
hitop_base_codevalues that already exist inontology/hitop.ttl. - A factorization adds no triples to the core ontology.
hitop:hasTierandhitop:hasLevelare declared in the core, but are only ever asserted inside a factorization file, never in the core itself. - The same concept can hold a different level in different factorizations. Level is therefore never a property of the class itself, only a statement inside one particular factorization — which is why
hitop:hasLevelis a free string rather than a fixed class enumerated in the core (see Vocabulary). - Every factorization version is its own, self-contained directory. A new version never touches an older version's directory.
- Factorization files are independent statements with provenance, status, and review level — analogous to the mapping artifacts in Mapping & harmonization.
- A factorization MAY group several existing concepts into a new grouping valid only within that one factorization, without creating a new concept in the core. Such a node is
kind: collection(see Vocabulary).
Structure¶
| File | Required | Meaning |
|---|---|---|
<version>_hierarchy.yaml |
Yes | Tree structure, provenance, ontology pin |
README.md |
Yes | Short description, citation, status |
<version>_factorization.ttl |
Generated | See Generated factorization ontology; never hand-maintained |
<factorization-id> is a stable kebab-case identifier — for example working-model, bass-ackwards, dzpg-mds, psychosis, externalizing, emotional-dysfunction. <version> is the hierarchy file's filename prefix (for example V1052k) — not a running count, but a stable identifier assigned once per curation run.
Vocabulary¶
The core defines a single open, extensible class for every concrete HiTOP concept:
| Class | Purpose |
|---|---|
hitop:O002sP (Tier) |
Every concrete HiTOP concept class (Internalizing, Anxiousness, …). Open, extensible. |
There is deliberately no class modeling "level" as a fixed set of core-enumerated subclasses (Factor, Superspectrum, Spectrum, Subfactor, Component, Trait). The number of possible levels is not exhaustively known — some factorizations need Subfactor, others additionally Sub-subfactor or deeper — and a concept's level assignment is factorization-dependent regardless (Principle 3). A fixed core class per level would force a core change for every new combination.
Two properties relate Tier concepts to each other:
| Aspect | hitop:hasTier |
hitop:hasLevel |
|---|---|---|
| Relation | Tier → Tier | Tier → String |
| YAML source | A node's children nesting |
A node's free-text level value |
| Function | Defines the parent-child relationship and therefore the tree's vertical order | Describes the role a concept plays within this factorization |
| Interpretation | Every child is exactly one step below its parent; depth is the number of hasTier steps from the root |
Values may include Spectrum, Component, or Sub-subfactor |
| Validation consequence | No separate rank list is required to determine vertical order | Levels are not checked against depth; irregular trees may skip ranks or reuse a level label at different depths |
RDF interpretation¶
hitop:hasTier uses HiTOP concept-class IRIs, such as hitop:P002nf,
directly as subject and object. In OWL 2 this is known as punning: the same IRI
identifies a class and also acts as an individual in the factorization.
- Reasoning boundary: These statements do not create automatic subclass relationships.
- Validation boundary: Referential-integrity and duplicate-code checks are
performed by
validation/test_factorizations.py.
Collection nodes¶
kind: collection · factorization-local grouping
Sometimes a factorization merges several existing concepts into a new node valid only within that one factorization — for example, merging Internalizing and Thought Disorder into one shared superspectrum. When that grouping is not an independent, reusable HiTOP construct from the cited literature, it is not added to the core as a new concept (that would violate Principle 1). It is instead modeled as a local skos:Collection node:
- YAML: the node gets
kind: collection(instead of the implicit defaultconcept); itscodeis a factorization-local id that is not checked againstontology/hitop.ttl. - Generated RDF: the node gets
rdf:type skos:Collectionand its own IRI in the factorization namespace (http://purl.org/hitop/factorizations/<id>/v<version>#<code>) instead of a core IRI. - Hierarchy: it carries
hitop:hasLevel(for example"Superspectrum") andhitop:hasTierto itschildrenexactly like any other node — the merged concepts (Internalizing, Thought Disorder) are simply its children. No separate property is needed to record "members" apart from "children".
This pattern follows the standard SKOS distinction between skos:Concept (a meaning-bearing unit, here: Tier) and skos:Collection (a purely organizational grouping with no concept identity of its own).
Hierarchy file format¶
The hierarchy file is the editable source of a factorization version. It keeps the identity and provenance of the version together with the actual concept tree, so reviewers can understand who created the structure, which ontology version it uses, and how its nodes are arranged without reading generated RDF.
Each <version>_hierarchy.yaml file has two top-level sections: meta records
the factorization's identity, status, source, ontology reference, and
provenance; hierarchy contains the recursive tree of concepts and optional
collection nodes. The example below shows their relationship. The schema then
checks the document against the maintained contract in
schema/factorization-hierarchy.schema.json
before any ontology or diagram artifact is generated.
meta:
factorization_id: working-model
version: V1052k
label: HiTOP Working Model
status: draft
source: data/hitop/images/hitop_working_model.png
based_on:
ontology_iri: "http://purl.org/hitop"
ontology_version: "0.1.0"
provenance:
created_by:
- orcid: "https://orcid.org/0000-0002-4505-4593"
name: "Rogério Blitz"
contributors:
- orcid: "https://orcid.org/0000-0002-4505-4593"
name: "Rogério Blitz"
contributions: "http://purl.org/hitop/contributions"
created_at: "2026-07-03"
hierarchy:
label: General Factor of Psychopathology (p-factor)
level: Factor
code: F001Hw
children:
- label: Externalizing
level: Superspectrum
code: S0013h
children: [...]
Download the YAML starter template
The starter template distinguishes required, conditional, and optional fields. Replace every <REPLACE_WITH_…> placeholder before validation. YAML comments document controlled values and when optional fields should be enabled; the commented-out children block shows the node shape to repeat for every level of the tree.
Field reference¶
This reference covers every meta and node field defined by schema/factorization-hierarchy.schema.json. It initially shows mandatory fields; use the filter to inspect conditional, optional, or all fields. Node rows apply to every node in the hierarchy tree, recursively, not only to the root.
validation/test_factorizations.py checks:
- schema conformance against
factorization-hierarchy.schema.json; - that every
kind: conceptnode'scode(recursively, across the whole tree) actually exists as a class inontology/hitop.ttl— referential integrity;kind: collectionnodes are exempt. Vertical order itself already follows structurally from thechildrennesting and is not checked separately;levelis deliberately not checked for depth consistency (see Vocabulary); - that no
codeoccurs twice within one tree; - that every
kind: conceptnode'slabelmatches therdfs:labelof its code inontology/hitop.ttl(case-insensitive;kind: collectionnodes are exempt) — this catches code collisions such as curation typos. Each factorization is checked against the core ontology only, never against other factorizations, because factorizations are authored independently. A synonym belongs in the core as a mapping; a construct with a different meaning is modelled askind: collection.
Generated factorization ontology¶
Each hierarchy can be published as a machine-readable factorization ontology. The generated artifact preserves the version's structure and provenance while linking every referenced concept back to its stable identity in the HiTOP core ontology. This makes a factorization independently citable and usable by other semantic-web tools without creating a second source of truth.
For every regular concept node, the generator additionally copies its rdfs:label (and, where present, rdfs:comment) from the core ontology into the generated file — purely for readability, so a factorization file is understandable on its own without looking up the IRI in the core. A concept's rdf:type and rdfs:subClassOf are never duplicated; the core ontology remains the sole source of truth for label and comment. These generated files are never hand-maintained — when the YAML changes, they are regenerated and the old versions replaced.
Command
.venv/bin/python scripts/generate_factorization_ontology.py \
factorizations/psychosis/v1/V10749_hierarchy.yaml
Output
{
"valid": true,
"input": "factorizations/psychosis/v1/V10749_hierarchy.yaml",
"output": [
"factorizations/psychosis/v1/V10749_factorization.rdf"
]
}
See the generated ontology this example produces.
Diagram data and the central color rule¶
Each factorization can also be explored as an interactive diagram. The diagram data is generated from the same reviewed hierarchy as the ontology artifact, so labels, levels, branches, and provenance remain consistent across the documentation and downloadable files. The generated data is a presentation format and is therefore rebuilt from the hierarchy rather than edited by hand.
Command
.venv/bin/python scripts/generate_factorization_diagram_data.py \
factorizations/psychosis/v1/V10749_hierarchy.yaml
Output
{
"valid": true,
"input": "factorizations/psychosis/v1/V10749_hierarchy.yaml",
"output": "factorizations/psychosis/v1/V10749_diagram.json"
}
See the generated diagram data this example produces.
Color assignment follows a single, factorization-wide rule (src/hitop/factorization/colors.py), so every diagram stays visually consistent:
- A fixed 24-color palette (from dark blue to light pink) is spread across every node whose
levelis in{Factor, Superspectrum, Spectrum, Subfactor}— each such node gets its own color, drawn directly from the palette. - The palette is spread in tree order (depth-first, the order the tree is written in the YAML), evenly across the whole palette regardless of how many such nodes a given factorization has. This produces a continuous color gradient along the tree structure, the same way the original HiTOP figures color a whole branch consistently.
ComponentandTraitnodes are not part of the palette. Each instead gets a lightened, slightly desaturated variant of its direct parent's color (HSL: lightness increased per depth step below the nearest palette node, saturation slightly reduced) — nested Component/Trait nodes get progressively lighter with each step.
This rule is deliberately encapsulated in its own module (hitop.factorization.colors), importable by both the diagram generator and any future renderer, instead of duplicating the color logic in a renderer. <version>_diagram.json is, like the other generated files, never hand-maintained. See the diagram viewer for every factorization rendered live with this rule.