Coverage for python/lsst/verify/report.py: 16%
49 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-11 02:05 -0700
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-11 02:05 -0700
1# This file is part of verify.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
21__all__ = ['Report']
23from astropy.table import Table
24import numpy as np
26from .naming import Name
29class Report(object):
30 r"""Report tabulating specification pass/fail status for a set of
31 `lsst.verify.Measurement`\ s.
33 Parameters
34 ----------
35 measurements : `lsst.verify.MeasurementSet`
36 Measurements to be tested.
37 specs : `lsst.verify.SpecificationSet`
38 Specifications to test measurements against. These specifications
39 are assumed to be relevant to the measurements. Use
40 `lsst.verify.SpecificationSet.subset`, passing in job metadata
41 (`lsst.verify.Job.meta`), to ensure this.
42 """
44 def __init__(self, measurements, specs):
45 self._meas_set = measurements
46 self._spec_set = specs
48 def make_table(self):
49 """Make an table summarizing specification tests of measurements.
51 Returns
52 -------
53 table : `astropy.table.Table`
54 Table with columns:
56 - **Status**
57 - **Specification**
58 - **Measurement**
59 - **Test**
60 - **Metric Tags**
61 - **Spec. Tags**
62 """
63 # Columns for the table
64 statuses = []
65 spec_name_items = []
66 measurements = []
67 tests = []
68 metric_tags = []
69 spec_tags = []
71 spec_names = list(self._spec_set.keys())
72 spec_names.sort()
74 for spec_name in spec_names:
75 # Test if there is a measurement for this specification,
76 # if not, we just skip it.
77 metric_name = Name(package=spec_name.package,
78 metric=spec_name.metric)
79 try:
80 meas = self._meas_set[metric_name]
81 except KeyError:
82 # No measurement for this specification, just skip it.
83 continue
85 spec = self._spec_set[spec_name]
87 if np.isnan(meas.quantity):
88 # Not measured
89 # https://emojipedia.org/heavy-minus-sign/
90 statuses.append(u'\U00002796')
91 elif spec.check(meas.quantity):
92 # Passed
93 # http://emojipedia.org/white-heavy-check-mark/
94 statuses.append(u'\U00002705')
95 else:
96 # Failed.
97 # http://emojipedia.org/cross-mark/
98 statuses.append(u'\U0000274C')
100 spec_name_items.append(str(spec_name))
102 measurements.append(meas._repr_latex_())
104 tests.append(spec._repr_latex_())
106 tags = list(spec.tags)
107 tags.sort()
108 spec_tags.append(', '.join(tags))
110 metric = meas.metric
111 if metric is None:
112 # no metric is available, this is the default
113 metric_tags.append('N/A')
114 else:
115 tags = list(metric.tags)
116 tags.sort()
117 metric_tags.append(', '.join(tags))
119 table = Table([statuses, spec_name_items, measurements, tests,
120 metric_tags, spec_tags],
121 names=['Status', 'Specification', 'Measurement', 'Test',
122 'Metric Tags', 'Spec. Tags'])
123 return table
125 def _repr_html_(self):
126 """HTML representation of the report for Jupyter notebooks."""
127 table = self.make_table()
128 return table._repr_html_()
130 def show(self):
131 """Display the report in a Jupyter notebook."""
132 table = self.make_table()
133 return table.show_in_notebook(show_row_index='')