Reports
A report is a document of what an analysis found: text, tables and figures. It is
saved as a file next to the results, and anyone can later turn it into HTML or LaTeX
without having the analyzer that made it installed. Reports live in
plesty.lib.report.
Making and reading a report
analyzer.report(outputs) returns the report for an analyzer’s outputs:
from plesty.lib.report import REPORT_SUFFIX, Report
outputs = analyzer(spectrum=sweep)
analyzer.report(outputs).save(run_dir / f"fine_structure{REPORT_SUFFIX}") # *.report.json
report = Report.load(run_dir / "fine_structure.report.json") # needs no analyzer
report.to_html() # an HTML fragment: tables, equations, figures as inline SVG
report.to_latex() # LaTeX: tables for the booktabs package, figures for pgfplots
to_html() shows equations as MathML with the report extra, and as their LaTeX
source without it (see Install).
The default report
Without any code, report() makes a table of every output that is a result. Each
entry of output_schema may say which it is, with a role:
"result"(the default): shown in the report;"intermediate": kept in the outputs but left out of the report, such as the single-line fits a final number was computed from.
An entry may also give a title for its table. A structured result such as a
SpectrumFitData is tabulated by the columns its type declares (see
Experiment data); a one-dimensional array
becomes one column; single numbers share one table.
Writing your own report
Override report() in the analyzer to say more: a sentence on the result, a table
laid out for a paper, a figure.
from plesty.lib.monitor import Line, Scatter
from plesty.lib.report import Cell, Figure, Report, Table, Value
def report(self, outputs):
return Report(
[
r"Two of four lines split by $\Delta E = 11.5 \pm 0.3$ µeV.",
Table(
header=[
[Cell("Line", rowspan=2), Cell("Splitting", colspan=2)],
[Cell(r"$\Delta E$ (µeV)"), Cell(r"$\Delta\lambda$ (pm)")],
],
rows=[[Cell("775.012 nm"), Value(11.5, err=0.3), Value(5.52, err=0.14)]],
),
Figure([Scatter(x=angles, y=centres), Line(x=angles, y=fitted)]),
],
title="Fine structure",
provenance=self.provenance(),
)
A report is a list of blocks, in order:
Block |
Holds |
|---|---|
a plain string, or |
a paragraph |
|
a table; each row is a list of cells |
|
a plot, made of the same drawables as a viewer’s plots (see The drawables) |
Cells. A Cell holds text, which may use **bold**, *italic*, `code`
and $math$. A Value(number, err=uncertainty) is shown with as many digits as its
uncertainty allows. A cell spans rows or columns with rowspan= and colspan=: it
is written once, where it starts, and the places it covers are left out of the rows
below and to its right. Every row must fill the table’s width and spans may not
overlap; a table that breaks this raises ReportError naming the row. For a table
these cells cannot express, Table.raw(html=..., latex=...) takes finished markup;
the HTML is cleaned before it is shown.
Ready-made tables. data_table(data) tabulates a structured result by the columns
its type declares, and array_table(array) tabulates one array as a single column,
headed by its name, unit and description. Both return None for something they cannot
tabulate, including anything longer than 200 rows (change the limit with max_rows=).
Reports outside analyzers
A report is not tied to an analyzer. An experiment can build one in a step and save it in its run folder, and a program that exports runs can collect the reports it finds there and render them.