xyReading, a IIIF extension for XY spectra (version 1)

xyReading tells a client how to read an XY curve (a spectrum) out of a Dataset content resource of a IIIF Presentation 3 document: which columns hold x and y, how their axes are titled, and which correction turns the raw file into the curve.

Where it appears

Only on a content resource of type Dataset, usually an annotation body. Any other resource MUST NOT carry it. A document that uses it lists this context first in its @context and the Presentation 3 context last:

"@context": ["https://manuspectrum.huma-num.fr/iiif/context/xy-reading/1.jsonld", "http://iiif.io/api/presentation/3/context.json"]

A document that also declares IIIF Authorization 2.0 services lists the Authorization 2.0 context between the two:

"@context": ["https://manuspectrum.huma-num.fr/iiif/context/xy-reading/1.jsonld", "http://iiif.io/api/auth/2/context.json", "http://iiif.io/api/presentation/3/context.json"]

The Presentation 2.1 routes carry the same object, with this context before the Presentation 2 context.

Advisory

Clients MAY use xyReading to draw the curve; they SHOULD fall back to their own reading of the file when they do not, and MUST ignore keys they do not know. Every key published is one the ManuSpectrum reader applies.

Keys

type: XYReading
The type of the object. Required.
conformsTo
The documentation of the version of xyReading the object follows (this page).
dialect
CSV dialect of the file (CSV on the Web terms): delimiter, headerRowCount, encoding. Given for the files ManuSpectrum writes.
columns
The columns read, in order: index (from 0) and role.
index
Zero-based index of a column.
role
What a column holds: x (the x axis), yLeft and yRight (a measurement on the left or right axis), reference (the white reference), dark (the dark current), ignore.
x
The x axis: label (a IIIF language map) and reversed (true when the axis is drawn from right to left; the rows keep the file's order).
y
The y axes, in order: axis (left or right) and label.
reversed
Whether the x axis is drawn from right to left.
multiY
How several measurement columns combine: reference-normalize divides the measurement by the reference (see corrections).
corrections
The corrections applied, in order. Version 1 knows reference-normalize: expression (y - dark) / (reference - dark), darkDefault the dark value without a dark column (0), epsilon the smallest denominator divided by, and onInvalid drop-point: a row with a missing value, a non-finite value or a denominator below epsilon is left out of the curve. An empty list says the file already holds the curve.
derivedFrom
The raw file the Dataset was derived from (PROV wasDerivedFrom): id, type, format, label and, for a raw text file, its own xyReading (columns and corrections).

The Dataset is never decimated, whatever its size. mirador-xyviewer does not plot a Dataset larger than 5 MB; such a file still plots in the ManuSpectrum Explorer.

Restricted data (IIIF Authorization)

Open data needs no credential. A restricted spectrum, annotation or content state answers 401 with a description that names the IIIF Authorization services; annotation pages and collections are never refused: they list what the reader may see and declare the same services.

  1. Login: the viewer opens https://manuspectrum.huma-num.fr/iiif/auth/login in a new window (IIIF Auth 1.0 login profile, Auth 2.0 active profile). The reader signs in to ManuSpectrum there; the window then says so and can be closed.
  2. Token: the viewer loads https://manuspectrum.huma-num.fr/iiif/auth/1/token (Auth 1.0) or https://manuspectrum.huma-num.fr/iiif/auth/2/token (Auth 2.0) in a hidden frame with its messageId and origin, and receives an access token valid 60 minutes for that origin only. It sends it as Authorization: Bearer <token> to the /iiif/ read routes; the Auth 2.0 probe service of a spectrum says whether that token opens it.
  3. Logout: opening https://manuspectrum.huma-num.fr/iiif/auth/logout in a tab (an HTTP GET, as IIIF Auth 1.0 defines it) ends every token of the session; signing out of ManuSpectrum does too. The ManuSpectrum session itself stays open.

The token only reads: it opens the /iiif/ routes and nothing else, and it is not an API credential. Tokens go only to this site and to the viewers its administrators trust; any other origin receives invalidOrigin. A Bearer token that is not a IIIF token of this site is refused.

Known limits

Versions

The major version is in the path of the context (/1). Version 1 only gains optional keys; a change of meaning would be version 2, at a new path.

JSON Schema (Draft 7): https://manuspectrum.huma-num.fr/iiif/context/xy-reading/1/schema.json. JSON-LD context: https://manuspectrum.huma-num.fr/iiif/context/xy-reading/1.jsonld.

Example

{
  "id": "https://manuspectrum.huma-num.fr/iiif/data/0f3a9c2d-0000-4000-8000-0000000000c7/series.csv",
  "type": "Dataset",
  "format": "text/csv",
  "xyReading": {
    "type": "XYReading",
    "conformsTo": "https://manuspectrum.huma-num.fr/iiif/context/xy-reading/1",
    "dialect": {
      "delimiter": ",",
      "headerRowCount": 1,
      "encoding": "utf-8"
    },
    "columns": [
      {
        "index": 0,
        "role": "x"
      },
      {
        "index": 1,
        "role": "yLeft"
      }
    ],
    "x": {
      "label": {
        "none": [
          "Wavelength (nm)"
        ]
      },
      "reversed": false
    },
    "y": [
      {
        "axis": "left",
        "label": {
          "none": [
            "Reflectance (0-1)"
          ]
        }
      }
    ],
    "corrections": [],
    "derivedFrom": {
      "id": "https://manuspectrum.huma-num.fr/iiif/data/0f3a9c2d-0000-4000-8000-0000000000c7/raw",
      "type": "Dataset",
      "format": "text/csv",
      "label": {
        "en": [
          "GRE76-FORS-0004.csv, raw file"
        ],
        "fr": [
          "GRE76-FORS-0004.csv, fichier brut"
        ]
      },
      "service": [
        {
          "@id": "https://manuspectrum.huma-num.fr/iiif/auth/login",
          "@type": "AuthCookieService1",
          "profile": "http://iiif.io/api/auth/1/login",
          "label": "Sign in to ManuSpectrum",
          "header": "Restricted data",
          "description": "Some data of ManuSpectrum are restricted. Sign in with your ManuSpectrum account to read what it gives access to.",
          "confirmLabel": "Sign in",
          "failureHeader": "Not available",
          "failureDescription": "Your account does not give access to these data.",
          "service": [
            {
              "@id": "https://manuspectrum.huma-num.fr/iiif/auth/1/token",
              "@type": "AuthTokenService1",
              "profile": "http://iiif.io/api/auth/1/token"
            },
            {
              "@id": "https://manuspectrum.huma-num.fr/iiif/auth/logout",
              "@type": "AuthLogoutService1",
              "profile": "http://iiif.io/api/auth/1/logout",
              "label": "Sign out of external viewers"
            }
          ]
        },
        {
          "id": "https://manuspectrum.huma-num.fr/iiif/auth/2/probe/0f3a9c2d-0000-4000-8000-0000000000c7",
          "type": "AuthProbeService2",
          "service": [
            {
              "id": "https://manuspectrum.huma-num.fr/iiif/auth/login",
              "type": "AuthAccessService2",
              "profile": "active",
              "label": {
                "en": [
                  "Sign in to ManuSpectrum"
                ],
                "fr": [
                  "Se connecter à ManuSpectrum"
                ]
              },
              "heading": {
                "en": [
                  "Restricted data"
                ],
                "fr": [
                  "Données restreintes"
                ]
              },
              "note": {
                "en": [
                  "Sign in with your ManuSpectrum account to read what it gives access to."
                ],
                "fr": [
                  "Connectez-vous avec votre compte ManuSpectrum pour lire les données auxquelles il donne accès."
                ]
              },
              "confirmLabel": {
                "en": [
                  "Sign in"
                ],
                "fr": [
                  "Se connecter"
                ]
              },
              "service": [
                {
                  "id": "https://manuspectrum.huma-num.fr/iiif/auth/2/token",
                  "type": "AuthAccessTokenService2",
                  "errorHeading": {
                    "en": [
                      "Not available"
                    ],
                    "fr": [
                      "Non disponible"
                    ]
                  },
                  "errorNote": {
                    "en": [
                      "Your account does not give access to these data."
                    ],
                    "fr": [
                      "Votre compte ne donne pas accès à ces données."
                    ]
                  }
                },
                {
                  "id": "https://manuspectrum.huma-num.fr/iiif/auth/logout",
                  "type": "AuthLogoutService2",
                  "label": {
                    "en": [
                      "Sign out of external viewers"
                    ],
                    "fr": [
                      "Se déconnecter des visionneuses externes"
                    ]
                  }
                }
              ]
            }
          ]
        }
      ],
      "xyReading": {
        "type": "XYReading",
        "conformsTo": "https://manuspectrum.huma-num.fr/iiif/context/xy-reading/1",
        "columns": [
          {
            "index": 0,
            "role": "x"
          },
          {
            "index": 1,
            "role": "yLeft"
          },
          {
            "index": 2,
            "role": "reference"
          }
        ],
        "multiY": "reference-normalize",
        "corrections": [
          {
            "type": "reference-normalize",
            "expression": "(y - dark) / (reference - dark)",
            "darkDefault": 0,
            "epsilon": 1e-12,
            "onInvalid": "drop-point"
          }
        ]
      }
    }
  }
}