Skip to content

Commit 85507ed

Browse files
authored
Merge pull request #430 from European-XFEL/feat/cal-reports-table
Add CalibrationData.reports_info() method
2 parents cc4051a + 39cc992 commit 85507ed

3 files changed

Lines changed: 72 additions & 0 deletions

File tree

docs/changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ Added:
2828
supports `DataCollection` objects to reference a point in time
2929
- [CalibrationData.from_correction][extra.calibration.CalibrationData.from_correction]
3030
method to find the constants used to correct a particular run.
31+
- [CalibrationData.reports_info][extra.calibration.CalibrationData.reports_info]
32+
method to show a summary of the reports associated with groups of calibration
33+
constants.
3134
- Pre-built packages will be available on PyPI for Python 3.10 - 3.13 from the
3235
next release, rather than only Python 3.10 (!377).
3336
- [Scan.group_data()][extra.components.Scan.group_data] method to make an xarray

src/extra/calibration.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,41 @@ def get_default_caldb_root():
305305
return _default_caldb_root
306306

307307

308+
def _summarise_mod_names(l):
309+
"""Group module names like 'LPD03' into contiguous numeric ranges
310+
311+
E.g. ['LPD00', 'LPD01', 'LPD03'] -> ['LPD00', 'LPD01'], ['LPD03']
312+
"""
313+
grp = []
314+
num_re = re.compile('(\d+)')
315+
316+
def extends_grp(split):
317+
if len(split) != len(grp[0]):
318+
return False
319+
320+
diffs_at = [i for i, (p1, p2) in enumerate(zip(grp[-1], split))
321+
if p1 != p2]
322+
if len(diffs_at) != 1 or ((diff_at := diffs_at[0]) % 2 == 0):
323+
return False # >1 part changed, or non-numeric part changed
324+
325+
if len(grp) > 2 and (grp[-1][diff_at] == grp[0][diff_at]):
326+
return False # different part changing from current seq
327+
328+
return int(grp[-1][diff_at]) + 1 == int(split[diff_at])
329+
330+
for mod in l:
331+
parts = num_re.split(mod) # parts 1, 3, ... are numeric
332+
333+
if grp and not extends_grp(parts):
334+
yield [''.join(p) for p in grp]
335+
grp = [parts]
336+
else:
337+
grp.append(parts)
338+
339+
if grp:
340+
yield [''.join(p) for p in grp]
341+
342+
308343
@dataclass
309344
class SingleConstant:
310345
"""A calibration constant for one detector module
@@ -1161,6 +1196,34 @@ def display_markdown_table(self, module_naming="modnum"):
11611196
from IPython.display import display, Markdown
11621197
display(Markdown(self.markdown_table(module_naming=module_naming)))
11631198

1199+
def reports_info(self):
1200+
"""Display information about the reports of found constants
1201+
"""
1202+
by_rept_id = {}
1203+
for cal, mmc in self.constant_groups.items():
1204+
for mod, sc in mmc.items():
1205+
rid = sc.metadata('report_id')
1206+
by_rept_id.setdefault(sc.metadata('report_id'), []).append((sc, cal, mod))
1207+
1208+
tbl = [['Report ID', 'Calibration types', 'Modules', '# constants', ]]
1209+
for report_id, consts in by_rept_id.items():
1210+
cals = sorted(set(t[1] for t in consts))
1211+
mods = sorted(set(t[2] for t in consts))
1212+
1213+
if report_id is not None:
1214+
# This is ugly, but avoids assuming production CalCat
1215+
ccv_url = consts[0][0].metadata('view_url')
1216+
calcat_base_url = ccv_url.split('/calibration_constant_versions/')[0]
1217+
report_details = str(report_id), f"{calcat_base_url}/reports/{report_id}"
1218+
else:
1219+
report_details = "(No report)"
1220+
1221+
mods_summary = [f"{g[0]}{g[-1]}" if len(g) > 1 else g[0]
1222+
for g in _summarise_mod_names(mods)]
1223+
1224+
tbl.append([report_details, ', '.join(cals), ', '.join(mods_summary), str(len(consts))])
1225+
1226+
return DisplayTables([tbl])
11641227

11651228
class ConditionsBase:
11661229
calibration_types = {} # For subclasses: {calibration: [parameter names]}

tests/test_calibration.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,12 @@ def test_AGIPD_from_correction():
321321
# available for lazy loading.
322322
assert agipd_cd["Offset", "AGIPD00"]._metadata['report_id'] == 6512
323323

324+
# Smoketest
325+
report_tbl = agipd_cd.reports_info()
326+
md = report_tbl._repr_markdown_()
327+
assert '[6512](https://in.xfel.eu/calibration/reports/6512)' in md
328+
report_tbl._repr_latex_()
329+
324330

325331
@pytest.mark.vcr
326332
def test_LPD_from_correction():

0 commit comments

Comments
 (0)