MIVOT (pyvo.mivot): Annotation Writer - Dev API

Introduction

Model Instances in VOTables (MIVOT) defines a syntax to map VOTable data to any model serialized in VO-DML. The annotation operates as a bridge between the data and the model. It associates the column/param metadata from the VOTable to the data model elements (class, attributes, types, etc.) […]. The data model elements are grouped in an independent annotation block complying with the MIVOT XML syntax. This annotation block is added as an extra resource element at the top of the VOTable result resource. The MIVOT syntax allows to describe a data structure as a hierarchy of classes. It is also able to represent relations and composition between them. It can also build up data model objects by aggregating instances from different tables of the VOTable (get more in MIVOT (pyvo.mivot)).

  • Model Instances in VOTables is a VO standard

  • Requires Astropy>=6.0

  • pyvo.mivot is a prototype feature which must be activated with activate_features("MIVOT")

Use the API

Build Annotation Object per Object

This documentation is intended for developers of data model classes who want to map them to VOTables and not for end users. A future version will allow end users to create annotations with ready-to-use data model building blocks.

Creating annotations consists of 3 steps:

  1. Create individual instances (INSTANCE) using the MivotInstance class: objects are built attribute by attribute. These components can then be aggregated into more complex objects following the structure of the mapped model(s).

  2. Wrap the annotations with the MivotAnnotations class: declare to the annotation builder the models used, and place individual instances at the right place (TEMPLATES or GLOBALS).

  3. Insert the annotations into a VOtable by using the Astropy API (wrapped in the package logic).

The annotation builder does not check whether the XML conforms to any particular model. It simply validates it against the MIVOT XML Schema if the xmlvalidator package if is installed.

The example below shows a step-by-step construction of a MIVOT block mapping a position with its error (as defined in the MANGO draft) and its space coordinate system (as defined in the Coordinates model and imported by MANGO).

Build the empty MIVOT Block

  • The MIVOT block consists of:

    • A process status

    • A list of mapped models

    • A list of globals, which are objects not associated with VOTable data and that can be shared by any other MIVOT instance.

    • A list of templates, which are objects that are connected to VOTable data and whose leaf values change from one row to another.

  • MIVOT is still an experimental feature which must be activated

from astropy.io.votable import parse
from pyvo.utils import activate_features
from pyvo.mivot.utils.exceptions import MappingException
from pyvo.mivot.utils.dict_utils import DictUtils
from pyvo.mivot.writer.annotations import MivotAnnotations
from pyvo.mivot.writer.instance import MivotInstance
from pyvo.mivot.viewer.mivot_viewer import MivotViewer

activate_features("MIVOT")

mivot_annotations = MivotAnnotations()
mivot_annotations.add_model(
    "ivoa", "https://www.ivoa.net/xml/VODML/IVOA-v1.vo-dml.xml"
)
mivot_annotations.add_model(
    "coords", "https://www.ivoa.net/xml/STC/20200908/Coords-v1.0.vo-dml.xml"
)
mivot_annotations.add_model(
    "mango",
    "https://raw.githubusercontent.com/lmichel/MANGO/draft-0.1/vo-dml/mango.vo-dml.xml",
)
mivot_annotations.set_report(True, "PyVO Tuto")

Build the Coordinate System Object

The space coordinate system is made of a space frame and a reference position, both wrapped in a coords:SpaceSys object (see the Coordinates data model).

The time coordinate system is made of a time frame and a reference position, both wrapped in a coords:TimeSys object.

  • Each of these objects have a dmid which will be used as a reference by the EpochPosition instance.

mivot_annotations.add_simple_space_frame(ref_frame="FK5",
                                         ref_position="BARYCENTER",
                                         equinox="J2000",
                                         dmid="_spacesys"
                                         )
mivot_annotations.add_simple_time_frame(ref_frame="TCB",
                                        ref_position="BARYCENTER",
                                        dmid="_timesys"
                                        )

Build the EpochPosition Object

  • In this example we only use the position attributes (RA/DEC) of the EpochPosition class.

  • The reference to the space coordinate system is added at the end.

  • The ref XML attributes reference columns that must be used to set the model attributes. Their values depend on the VOTable to be mapped.

from astropy.io.votable import parse
from pyvo.utils import activate_features
from pyvo.mivot.utils.exceptions import MappingException
from pyvo.mivot.utils.dict_utils import DictUtils
from pyvo.mivot.writer.annotations import MivotAnnotations
from pyvo.mivot.writer.instance import MivotInstance
from pyvo.mivot.viewer.mivot_viewer import MivotViewer

activate_features("MIVOT")

position = MivotInstance(dmtype="mango:EpochPosition")
position.add_attribute(
    dmtype="ivoa:RealQuantity",
    dmrole="mango:EpochPosition.longitude",
    unit="deg",
    ref="RAICRS",
)
position.add_attribute(
    dmtype="ivoa:RealQuantity",
    dmrole="mango:EpochPosition.latitude",
    unit="deg",
    ref="DEICRS",
)
position.add_reference(
    dmref="_spacesys", dmrole="mango:EpochPosition.spaceSys"
)

Build the Position Error

  • We assume that the position error is the same on both axes without correlation. In terms of MANGO error, this corresponds to a 2x2 diagonal error matrix with two equal coefficients.

  • Finally, the error is added as a component of the EpochPosition instance.

epoch_position_error = MivotInstance(
    dmtype="mango:EpochPositionErrors", dmrole="mango:EpochPosition.errors"
)
position_error = MivotInstance(
    dmtype="mango:error.ErrorCorrMatrix",
    dmrole="mango:EpochPositionErrors.position",
)
position_error.add_attribute(
    dmtype="ivoa:RealQuantity",
    dmrole="mango:error.ErrorCorrMatrix.sigma1",
    unit="arcsec",
    ref="sigm",
)
position_error.add_attribute(
    dmtype="ivoa:RealQuantity",
    dmrole="mango:error.ErrorCorrMatrix.sigma2",
    unit="arcsec",
    ref="sigm",
)
epoch_position_error.add_instance(position_error)
position.add_instance(epoch_position_error)

Pack the MIVOT Block

  • Pack the model instances previously built.

  • The latest step (build_mivot_block) includes a validation of the MIVOT syntax that works only if the xmlvalidator package has been installed.

mivot_annotations.add_templates(position)
mivot_annotations.build_mivot_block()

Insert the MIVOT Block in a VOTable

  • This straightforward step is based on the Astropy VOTable API.

  • Annotations are stored in-memory (in the parsed VOtable).

  • The mapping can be tested with the MivotViewer API (see the MIVOT (pyvo.mivot): Annotation Viewer - Public API)

  • The VOtable must be explicitly saved on disk if needed.

from astropy.io.votable import parse

votable = parse(votable_path)
mivot_annotations.insert_into_votable(votable)

mivot_viewer = MivotViewer(votable)
mapped_instance = mivot_viewer.dm_instance

votable.to_xml("pyvo-tuto.xml")

Validate the annotations against the models

  • This action requires the mivot-validatorXXX package to be installed.

  • It validates the mapped classes against the models they come from.

% pip install mivot-validator
% mivot-instance-validate pyvo-tuto.xml
...
Valid if no error message
...