It is much easier to use advantages of Sardana and write NeXus files with NXS_FileRecorder using scan macros like ascan, dscan or extend them if it is needed to add new features or write a simple Sardana scan macro, e.g.
#!/bin/env python """ NeXus recorder macros """ import time import os import datetime from sardana.macroserver.macro import Macro, Type from sardana.macroserver.msexception import UnknownEnv from sardana.macroserver.scan.recorder import DataHandler from sardana.macroserver.scan.scandata import \ ScanData, ScanDataEnvironment, ColumnDesc # test user data of ch1, ch2 and ch3 channels data = { 'ch1': [10., 23.4, 12., 234., 16.], 'ch2': [20., 21., 22., 23., 24.], 'ch3': [32., 33., 34., 35., 36.] } class nxsscan(Macro): """ Two motor scan with a direct Recorder usage """ param_def = [ ['motor1', Type.String, ”, 'first motor name'], ['motor2', Type.String, ”, 'second motor name'], ] def prepare(self, motor1, motor2): # get output file name from the environment scan_dir = self.getEnv("ScanDir") scan_file = self.getEnv("ScanFile") if isinstance(scan_file, list): scan_file = scan_file[0] file_name = os.path.join(scan_dir, scan_file) # construct NXS_FileRecorder rec_manager = self.getMacroServer().recorder_manager nx_recorder = rec_manager.getRecorderClass( "NXS_FileRecorder")(file_name, macro=self) # construct data handler data_handler = DataHandler() data_handler.addRecorder(nx_recorder) # increase the scanID try: serialno = self.getEnv("ScanID") + 1 except UnknownEnv: serialno = 1 self.setEnv("ScanID", serialno) # prepare scan data environment env = ScanDataEnvironment( {'serialno': self.getEnv("ScanID"), 'title': "NeXus scan example"} ) env['ScanDir'] = scan_dir env['ScanFile'] = scan_file env['starttime'] = datetime.datetime.fromtimestamp(time.time()) # add motors ref_moveables = [] if motor1: ref_moveables.append(motor1) if motor2: ref_moveables.append(motor2) env['ref_moveables'] = ref_moveables # add channel description data_desc = [] data_desc.append( ColumnDesc(name='point_nb', label='#Pt No', dtype='int64')) data_desc.append( ColumnDesc(name='timestamp', label='dt', dtype='float64')) # add user channels for i, col in enumerate(data.keys()): data_desc.append( ColumnDesc(name=col, label=col, dtype='float64')) env['datadesc'] = data_desc self._env = env # construct ScanData object self._data = ScanData(environment=env, data_handler=data_handler, apply_interpolation=False) self._data.initial_data = {} def run(self, motor1, motor2): # write data in the INIT mode self._data.start() # STEP scan loop for i in range(5): self.output("Point No: %s" % self._data.recordno) self._data.initial_data[i] = {"timestamp": time.time()} for name, v in data.items(): self._data.addData( {"index": [i], "label": name, "value": [v[i]]}) time.sleep(0.1) # write data in the FINAL mode self._env['endtime'] = datetime.datetime.fromtimestamp(time.time()) self._data.end()
The above macro works for sardana 3.0 (debian 10).