.. _reporting: Reporting ========= This tutorial will cover using :py:class:`vspyx.Reporting.Module` to easily create reports in |project|. Setup ----- This tutorial will build on the work of :ref:`signalvalues`. If you have not completed that tutorial, a finished example is availble at its bottom. We will use numpy_ and matplotlib_ for numerical processing generating plots. These packages can be installed with pip_. .. _numpy: https://numpy.org/ .. _matplotlib: https://matplotlib.org/ .. _pip: https://pip.pypa.io/en/stable/installing/ .. code:: shell pip3 install matplotlib numpy Creating an empty report ------------------------ A new report is created by calling :py:func:`vspyx.Reporting.Module.NewReport`. .. code:: python report = app.Reporting.NewReport() report.Title = "My Report" Adding content -------------- For the report to be useful, we need to add some content to it. Referring back to :ref:`signalvalues`, we will add a new section to the report for every signal that was individually requested. We will then append to a list all values for the signal, giving us the ability to process these after the entire buffer is finished. Every report has a :py:attr:`vspyx.Reporting.Report.RootSection`. New subsections can be added by calling :py:func:`vspyx.Reporting.Section.NewSection`. .. code:: python # at global scope import matplotlib matplotlib.use("agg") import matplotlib.pyplot as pyplot pyplot.ioff() import numpy signal_points = {} # in on_trace_point if point.Traceable not in signal_points: signal_points[point.Traceable] = [point] else: signal_points[point.Traceable].append(point) # before looping over all signals sections = {} # after trace.OnPoint.Add(on_trace_point) sections[signal] = report.RootSection.NewSection() sections[signal].Name = signal_id We now have a report section defined for each signal, as well as all of the signal points. Here, we will calculate some statistics on the each signal with ``numpy`` and use ``matplotlib`` to generate a plot. .. code:: python # after app.VehicleSpy.Stop() for signal, points in signal_points.items(): timestamps = [(x.Timestamp - points[0].Timestamp).total_seconds() for x in points] values = [x.PhysicalValue for x in points] min = numpy.min(values) max = numpy.max(values) std_dev = numpy.std(values) average = numpy.average(values) stats = sections[signal].NewTable() stats.SetHeader(["Statistic", "Value"]) stats.AddRow(["min", str(min)]) stats.AddRow(["max", str(max)]) stats.AddRow(["average", str(average)]) stats.AddRow(["std dev", str(std_dev)]) pyplot.clf() _, axis = pyplot.subplots() axis.plot(timestamps, values, label=signal.ID) axis.set_ylabel(signal.ID) axis.set_xlabel("Time (s)") pyplot.savefig(f"{signal.ID}.png", format='png') sections[signal].NewImage(f"{signal.ID}.png") Generating the report ---------------------- :py:class:`vspyx.Reporting.Report` has two functions for generating the actual report: :py:func:`vspyx.Reporting.Report.BuildHTML` and :py:func:`vspyx.Reporting.Report.BuildPDF`. Since generating the report may take some time, these functions immediately return a :py:class:`vspyx.Core.Task_bool_t`. This task can either by synchronously executed, or ran in the background. .. code:: python report.BuildHTML("report.html").Execute() report.BuildPDF("report.pdf").Execute() Example output -------------- .. raw:: html

My Report

RPM

Statistic Value
min 0
max 3293
average 2660.7385486361295
std dev 432.96441048025554
_images/RPM.png