R3XA_API — Overview and rationale

This page is an explanation page. It focuses on concepts, design rationale, and the high-level data model. If you want to learn the library hands-on, start with notebooks.md.

R3XA logo

Credits and origin

  • Initial implementation by E. Roubin, based on a shared specification led by J‑C. Passieux.

  • Original upstream repository: https://gitlab.com/photomecanics/r3xa

  • Current public repository: https://github.com/jeffwitz/R3XA_API

Why R3XA

Researchers often lose crucial experimental context (camera focal length, calibration targets, acquisition settings). R3XA proposes a metadata standard to help remember, reuse, and replicate experiments without inventing a new data format.

Core idea

  • Not another file format: R3XA is a metadata layer over existing data files.

  • JSON Schema: human‑readable, tool‑friendly, and easy to validate.

  • Shareable and scalable: structured but extensible as practices evolve.

JSON structure (high level)

An R3XA file is a single JSON document composed of:

  • header fields (version, title, description, authors, date, …)

  • settings: experimental parameters and devices

  • data_sources: sensors or analysis steps that produce data

  • data_sets: the actual datasets and their time/space organization

Structure diagram

        graph TD
  R3XA["R3XA JSON"]
  H["Header (version, title, description, authors, date, ...)"]
  S["settings[]"]
  DS["data_sources[]"]
  DSET["data_sets[]"]

  R3XA --> H
  R3XA --> S
  R3XA --> DS
  R3XA --> DSET
    

Header (minimal)

Required fields:

  • version, title, description, authors, date

Example:

{
  "version": "2024.7.1",
  "title": "Hello World",
  "description": "Minimal R3XA file",
  "authors": "JC Passieux",
  "date": "2024-10-30",
  "settings": [],
  "data_sources": [],
  "data_sets": []
}

Settings

Describe experimental parameters not directly linked to a specific dataset (specimen, machine, lighting, environment, …).

Example (generic):

{
  "id": "id0",
  "kind": "settings/generic",
  "title": "Testing machine",
  "description": "Instron 5800 — electromechanical tensile machine"
}

Example (specimen):

{
  "id": "id1",
  "kind": "settings/specimen",
  "title": "Openhole sample",
  "description": "The sample is a glass epoxy",
  "sizes": [
    {"kind": "unit", "title": "width", "value": 30.0, "unit": "mm", "scale": 1.0}
  ],
  "patterning_technique": "white background with black spray paint"
}

Data sources

A data source is a system or procedure that produces a dataset (camera, DIC, FEA, load cell, …).

Example (camera):

{
  "id": "id3",
  "kind": "data_sources/camera",
  "title": "CCD Camera",
  "description": "Encoding: 8-bit",
  "output_components": 1,
  "output_dimension": "surface",
  "output_units": [
    {"kind": "unit", "title": "graylevel", "value": 1.0, "unit": "gl", "scale": 1.0}
  ],
  "manufacturer": "Allied Vision Technologies (AVT)",
  "model": "Dolphin F-145B",
  "image_size": [
    {"kind": "unit", "title": "width", "value": 1392, "unit": "px", "scale": 1.0},
    {"kind": "unit", "title": "height", "value": 1040, "unit": "px", "scale": 1.0}
  ]
}

Flow diagram

        flowchart LR
  Setting[Settings] --> Source[Data source] --> Dataset[Data set]
  Setting -. context .-> Source
    

Data sets

A data set describes where the data lives and how it is organized in time.

Example (list of files):

{
  "id": "id4",
  "kind": "data_sets/list",
  "title": "graylevel images",
  "description": "images taken by the CCD camera",
  "path": "images/",
  "file_type": "image/tiff",
  "data_sources": ["id3"],
  "time_reference": {"kind": "unit", "title": "time_reference", "value": 0.0, "unit": "s", "scale": 1.0},
  "timestamps": [0.0, 1.0],
  "data": ["img_0001.tif", "img_0002.tif"]
}

Example (tabular files):

{
  "id": "id5",
  "kind": "data_sets/file",
  "title": "force time series",
  "description": "force vs time",
  "folder": "data/",
  "data_sources": ["id3"],
  "time_reference": 0.0,
  "timestamps": {"kind": "data_set_file", "filename": "timestamps.csv", "file_type": "text/csv"},
  "data": {"kind": "data_set_file", "filename": "force.csv", "file_type": "text/csv"}
}

Using the SDK

The SDK provides guided helpers to create these structures without writing raw JSON:

from r3xa_api import R3XAFile, unit

r3xa = R3XAFile(
    title="Hello World",
    description="Minimal R3XA file",
    authors="JC Passieux",
    date="2024-10-30",
)

specimen = r3xa.add_specimen_setting(
    title="Openhole sample",
    description="Glass-epoxy specimen",
    sizes=[unit(title="width", value=30.0, unit="mm", scale=1.0)],
)

camera = r3xa.add_camera_source(
    title="CCD Camera",
    description="Encoding: 8-bit",
    output_components=1,
    output_dimension="surface",
    output_units=[unit(title="graylevel", value=1.0, unit="gl", scale=1.0)],
    manufacturer="Allied Vision Technologies (AVT)",
    model="Dolphin F-145B",
    image_size=[
        unit(title="width", value=1392, unit="px", scale=1.0),
        unit(title="height", value=1040, unit="px", scale=1.0),
    ],
)

r3xa.add_image_set_list(
    title="graylevel images",
    description="images taken by the CCD camera",
    path="images/",
    file_type="image/tiff",
    data_sources=[camera["id"]],
    time_reference=unit(title="time_reference", value=0.0, unit="s", scale=1.0),
    timestamps=[0.0, 1.0],
    data=["img_0001.tif", "img_0002.tif"],
)

r3xa.validate()

Validation (why it matters)

R3XA is defined by a JSON Schema. Validation ensures:

  • Completeness: required fields are present.

  • Consistency: field types and allowed values are respected.

  • Reproducibility: datasets can be reused by others without guessing missing metadata.

Full file validation

Validate a complete R3XA file:

r3xa.validate()

Item validation (registry)

Registry items are validated against their own schema (e.g. data_sources/camera) so they can be reused safely:

from r3xa_api import validate_item
validate_item(camera_item)

See also: validation.md

Registry (reusable components)

To avoid rewriting camera/specimen/software definitions, store reusable items in a registry tree:

registry/
  settings/
    generic/
    specimen/
  data_sources/
    camera/
    generic/
  data_sets/
    list/
    file/

Each file is a single JSON item (not a full R3XA file) that can be loaded and validated individually. Registry entries are not only reusable templates: they can also be generated directly with the API, validated on their own, and saved back into the registry tree.

Built-in registry templates already shipped with the repository include:

  • settings/generic/instron_5800

  • data_sets/list/camera_images_template

  • data_sets/file/tabular_timeseries_template

How to load registry items

from r3xa_api import Registry

registry = Registry("registry")

specimen = registry.load("settings/specimen/openhole_sample")
camera = registry.load("data_sources/camera/avt_dolphin_f145b")
pyxel = registry.load("data_sources/generic/pyxel_dic_2d")

When you want item-level helpers such as merge(...), validate(), or save(...), load the same entry as a RegistryItem:

from r3xa_api import Registry

registry = Registry("registry")
camera_item = registry.get_item("data_sources/camera/avt_dolphin_f145b")

How to create a new registry item

from r3xa_api import Registry, new_item, unit

registry = Registry("registry")

camera = new_item(
    "data_sources/camera",
    id="ds_cam_example_generated",
    title="Example generated camera",
    description="Example registry camera generated with R3XA_API",
    output_components=1,
    output_dimension="surface",
    output_units=[unit(title="graylevel", value=1.0, unit="gl", scale=1.0)],
    manufacturer="Example manufacturer",
    model="Example model",
    image_size=[
        unit(title="width", value=2048, unit="px", scale=1.0),
        unit(title="height", value=1536, unit="px", scale=1.0),
    ],
)

registry.wrap(camera, tree_path="data_sources/camera/example_generated_camera").save()

This is the pattern used in examples/python/create_registry_camera.py.

How to reuse and override a registry item

from r3xa_api import Registry

registry = Registry("registry")

camera = registry.get_item("data_sources/camera/avt_dolphin_f145b").merge(
    id="ds_cam_exp01",
    description="Camera used in experiment 01",
)

camera.save("camera_exp01.json")

How it maps to the schema

  • Path registry/settings/specimen/*.json → items with kind = "settings/specimen"

  • Path registry/data_sources/camera/*.json → items with kind = "data_sources/camera"

  • Path registry/data_sources/generic/*.json → items with kind = "data_sources/generic"

  • Path registry/data_sets/list/*.json → items with kind = "data_sets/list"

  • Path registry/data_sets/file/*.json → items with kind = "data_sets/file"

Why sub-validation works

Each registry item is validated against its own schema definition (e.g. data_sources/camera) rather than the full R3XA schema, which keeps the registry modular and reusable.