Advanced features#

The following language features are experimental, behavior is not guaranteed to stay consistent

LinkML Any type#

LinkML is currently best suited to ‘strict’ schemas, and doesn’t have full support for being able to model arbitrary dictionaries/objects. Each slot must have a defined range, the range must be exactly one of a Class, Type, or Enum. It is currently impossible to define unions of these core ranges.

The linkml:Any type is an experimental feature for allowing arbitrary objects

classes:

  MetaObject:
    class_uri: linkml:Any

  ...

  Person:
   attributes:
     id:
     name:
     metadata:
       range: MetaObject

Unions as ranges#

any_of can be used to express that a range must satisfy any of a set of ranges.

One way this can be used is to compose enums together, for example if we have a vital_status enum that can take on any a set of enums from VitalStatus OR a missing value with the type of missing value defined by an enum:

slots:
  vital_status:
    required: true
    any_of:
      - range: MissingValueEnum
      - range: VitalStatusEnum
enums:
  MissingValueEnum:
    permissible_values:
      INAPPLICABLE:
      NOT_COLLECTED:
      RESTRICTED:
      OTHER:
  VitalStatusEnum:
    permissible_values:
      LIVING:
      DEAD:
      UNDEAD:

Note that these constructs may ignored by some generators in the linkml 1.1 series.

In the 1.2 series:

  • generated python should use a Union

  • jsonschema should use conditionals

  • OWL should use UnionOf

Rules#

Any class can have a rules block, consisting of (optional) preconditions and postconditions. This can express basic if-then logic:

classes:
  Address:
    slots:
      - street_address
      - country
    rules:
      - preconditions:
          slot_conditions:
            country:
              any_of:
                - equals_string: USA
                - equals_string: USA_territory
        postconditions:
          slot_conditions:
            postal_code:
              pattern: "[0-9]{5}(-[0-9]{4})?"
            telephone:
              pattern: "^\\+1 "
        description: USA and territories must have a specific regex pattern for postal codes and phone numbers

See above for implementation status

Defining slots#

A subset of slots for a class can be declared as defining slots, indicating that membership of the class can be inferred based on ranges of those slots

classes:

  Interaction:
    slots:
      - subject
      - object

  ProteinProteinInteraction:
    is_a: Interaction
    slot_usage:
      subject:
        range: Protein
      object:
        range: Protein
    defining_slots:
      - subject
      - object

This indicates that if we have an interaction object I, and the subject and object slot values for I are both of type Protein, then I can be inferred to be of type ProteinProteinInteraction

When translating to OWL, this will make an equilance axiom:

ProteinProteinInteraction = Interaction and subject some Protein and object some Protein

And using an OWL reasoner will give the intended inferences.

This feature is experimental, and may be replaced by a more general rules mechanism in future.

equals_expression#

equals_expression can be used to specify that the value of a slot should be equal to an evaluable expression, where that expression can contain other slot values as terms.

For example, a schema may allow two separate age slots for specifying age in years or in months. equals_expression is used to specify one in terns of another:

slots:
  ...
  age_in_years:
    range: decimal
    minimum_value: 0
    maximum_value: 999
    equals_expression: "{age_in_months} / 12"
  age_in_months:
    range: decimal
    equals_expression: "{age_in_years} * 12"
  is_juvenile:
    range: boolean
    equals_expression: "{age_in_years} < 18"

The expression is specified using a simple subset of Python. Slot names may be enclosed in curly braces - if any of the slot values is None then the entire expression evaluates to None.

You can insert missing values by using the --infer option when running linkml-convert.

Documentation of the expression language is available here.

See the developer documentation on inference for details of how to use this in code.