An Analyzer

An analyzer turns recorded data into a result, without touching an instrument. This page writes one that finds the wavelength where a power scan peaks, runs it on the scan from An Experiment, and saves what it found as a report.

Write the analyzer

An analyzer is a class based on Analyzer. It declares:

  • input_schema: the inputs it takes, each with a type, a unit and a description;

  • output_schema: the outputs it gives, described the same way;

  • analyze(): the calculation, taking the inputs as arguments and returning a dictionary with one entry per output.

# power_peak.py
import numpy as np

from plesty.lib.analyzer import Analyzer
from plesty.lib.data import PlestyArray


class PowerPeak(Analyzer):
    input_schema = {
        "wavelength": {"dtype": "array_float", "unit": "nm", "description": "Scan wavelengths."},
        "power": {"dtype": "array_float", "unit": "W", "description": "Power at each wavelength."},
    }
    output_schema = {
        "normalized": {"dtype": "array_float", "unit": "a.u.",
                       "description": "Power scaled to a peak of 1."},
        "peak_wavelength": {"dtype": "float", "unit": "nm",
                            "description": "Wavelength of the largest power."},
    }

    def analyze(self, wavelength: PlestyArray, power: PlestyArray) -> dict:
        peak = float(power.max()) or 1.0
        return {
            "normalized": PlestyArray(power / peak),
            "peak_wavelength": float(wavelength[int(np.argmax(power))]),
        }

"array_float" means an array of floating-point numbers, and "float" a single number. Data & Metadata Schemas lists every type an analyzer can take and give.

PlestyArray is a NumPy array that also carries a name, a unit and a description. You can pass a plain NumPy array as an input: the analyzer converts it and attaches the unit from input_schema.

Call it

You do not call analyze() yourself. Call the analyzer object, and it checks your data on the way in and out:

  1. the inputs must match input_schema: right names, right types;

  2. analyze() runs;

  3. the outputs must match output_schema, and any unit or description missing from them is taken from it;

  4. every array in the outputs records how it was made: by which analyzer, which version of its package, and with which settings. This record is called its provenance.

import numpy as np

from power_peak import PowerPeak

analyzer = PowerPeak()
outputs = analyzer(wavelength=np.array([500.0, 600.0, 700.0]),
                   power=np.array([0.002, 0.008, 0.004]))

print(outputs["peak_wavelength"])          # 600.0
print(outputs["normalized"].unit)          # a.u.
print(outputs["normalized"].provenance)    # {'analyzer': 'PowerPeak', ...}

Run it on a recorded scan

The records of a run (see Run it and read the result) are dictionaries, one per finished step. Collect the values the analyzer needs into arrays and call it:

import numpy as np

from plesty.lib.experiment import Run, latest_run
from power_peak import PowerPeak

run = Run(latest_run("runs", name="powerscan"))
records = list(run.records())
outputs = PowerPeak()(
    wavelength=np.array([r["wavelength_nm"] for r in records]),
    power=np.array([r["power_w"] for r in records]),
)
print(outputs["peak_wavelength"])

Save a report

A report is a document of what an analysis found: tables, figures and text. report(outputs) makes one; by default it has a table of every output. Save it as a file, and anyone can turn it into HTML or LaTeX later, without having your analyzer installed:

from pathlib import Path

from plesty.lib.report import REPORT_SUFFIX, Report

path = Path(run.path) / f"power_peak{REPORT_SUFFIX}"     # REPORT_SUFFIX is ".report.json"
PowerPeak().report(outputs).save(path)

html = Report.load(path).to_html()                      # or .to_latex()

To write your own report, with a sentence about the result, a table laid out for a paper, or a plot, override report() in your analyzer. Reports shows how.

Advanced topics

You want to …

Read

know every rule an analyzer’s schemas and outputs must follow

The contract

know which parts of the analyzer API will not change in later plesty-lib versions

What will not change

write your own report: a sentence on the result, a table laid out for a paper, a figure

Reports

take a spectrum, or another structured measurement, as input

Experiment data

fit the peaks of a spectrum with the analyzer that comes with plesty-lib

SpectrumFit

test your analyzer automatically

Testing an Analyzer