spec2nexus.eznx

(Easy NeXus) support library for reading & writing NeXus HDF5 files using h5py

How to use spec2nexus.eznx

Here is a simple example to write a NeXus data file using eznx:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Writes a simple NeXus HDF5 file using h5py with links.

This example is based on ``writer_2_1`` of the NeXus Manual:
http://download.nexusformat.org/doc/html/examples/h5py/index.html
"""

from spec2nexus import eznx


HDF5_FILE = "eznx_example.hdf5"

I_v_TTH_DATA = """
17.92608    1037
17.92558    2857
17.92508    23819
17.92458    49087
17.92408    66802
17.92358    66206
17.92308    64129
17.92258    56795
17.92208    29315
17.92158    6622
17.92108    1321
"""
# ---------------------------

tthData, countsData = zip(
    *[map(float, _.split()) for _ in I_v_TTH_DATA.strip().splitlines()]
)

f = eznx.makeFile(HDF5_FILE)  # create the HDF5 NeXus file
f.attrs["default"] = "entry"

nxentry = eznx.makeGroup(f, "entry", "NXentry", default="data")
nxinstrument = eznx.makeGroup(nxentry, "instrument", "NXinstrument")
nxdetector = eznx.makeGroup(nxinstrument, "detector", "NXdetector")

tth = eznx.makeDataset(nxdetector, "two_theta", tthData, units="degrees")
counts = eznx.makeDataset(nxdetector, "counts", countsData, units="counts")

nxdata = eznx.makeGroup(
    nxentry,
    "data",
    "NXdata",
    signal=1,
    axes="two_theta",
    two_theta_indices=0,
)
eznx.makeLink(nxdetector, tth, nxdata.name + "/two_theta")
eznx.makeLink(nxdetector, counts, nxdata.name + "/counts")

f.close()  # be CERTAIN to close the file

The output of this code is an HDF5 file (binary). It has this structure:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    eznx_example.hdf5:NeXus data file
      @default = entry
      entry:NXentry
        @NX_class = NXentry
        @default = data
        data:NXdata
          @NX_class = NXdata
          @signal = counts
          @axes = two_theta
          @two_theta_indices = 0
          counts --> /entry/instrument/detector/counts
          two_theta --> /entry/instrument/detector/two_theta
        instrument:NXinstrument
          @NX_class = NXinstrument
          detector:NXdetector
            @NX_class = NXdetector
            counts:NX_FLOAT64[11] = __array
              @units = counts
              @target = /entry/instrument/detector/counts
              __array = [1037.0, 2857.0, 23819.0, '...', 1321.0]
            two_theta:NX_FLOAT64[11] = __array
              @units = degrees
              @target = /entry/instrument/detector/two_theta
              __array = [17.926079999999999, 17.92558, 17.925080000000001, '...', 17.92108]

NeXus HDF5 File Structure

The output of this code is an HDF5 file (binary). It has this general structure (indentation shows HDF5 groups, @ signs describe attributes of the preceding item):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  hdf5_file:NeXus data file
     @default = S1
     S1:NXentry     (one NXentry for each scan)
        @default = data
        title = #S
        T or M: #T or #M
        comments: #C for entire scan
        date: #D
        scan_number: #S
        G:NXcollection
           @description = SPEC geometry arrays, meanings defined by SPEC diffractometer support
           G0:NX_FLOAT64[] #G0
           G1:NX_FLOAT64[] #G1
           ...
        data:NXdata
           @description = SPEC scan data (content from #L and data lines)
           @signal = I0
           @axes = mr
           @mr_indices = 0
           Epoch:NX_FLOAT64[]
           I0:NX_FLOAT64[]         (last data column)
             @spec_name = I0
           mr:NX_FLOAT64[]         (first data column)
           ...
        metadata:NXcollection
           @description = SPEC metadata (UNICAT-style #H & #V lines)
           ARenc_0:NX_FLOAT64 = 0.0
           ...
        positioners:NXcollection
           @description = SPEC positioners (#P & #O lines)
           mr:NX_FLOAT64
           ...

APIs provided:


source code methods

addAttributes add attributes to an h5py data item
makeFile create and open an empty NeXus HDF5 file using h5py
makeDataset create and write data to a dataset in the HDF5 file hierarchy
makeExternalLink create an external link from sourceFile, sourcePath to targetPath in hdf5FileObject
makeGroup create a NeXus group
openGroup open or create the NeXus/HDF5 group, return the object
makeLink create an internal NeXus (hard) link in an HDF5 file
read_nexus_field get a dataset from the HDF5 parent group
read_nexus_group_fields return the fields in the NeXus group as a dict(name=dataset)
write_dataset write to the NeXus/HDF5 dataset, create it if necessary, return the object

source code documentation

(Easy NeXus) support reading & writing NeXus HDF5 files using h5py

predecessor:NeXus h5py example code: my_lib.py [1]
[1]http://download.nexusformat.org/doc/html/examples/h5py/index.html#mylib-support-module

Dependencies

  • h5py: interface to HDF5 file format

Exceptions raised

  • None

Example

root = eznx.makeFile('test.h5', creator='eznx', default='entry')
nxentry = eznx.makeGroup(root, 'entry', 'NXentry', default='data')
ds = eznx.write_dataset(nxentry, 'title', 'simple test data')
nxdata = eznx.makeGroup(nxentry, 'data', 'NXdata', signal='counts', axes='tth', tth_indices=0)
ds = eznx.write_dataset(nxdata, 'tth', [10.0, 10.1, 10.2, 10.3], units='degrees')
ds = eznx.write_dataset(nxdata, 'counts', [1, 50, 1000, 5], units='counts', axes="tth")
root.close()

The resulting (binary) data file has this structure:

test.h5:NeXus data file
  @creator = eznx
  @default = 'entry'
  entry:NXentry
    @NX_class = NXentry
    @default = 'data'
    title:NX_CHAR = simple test data
    data:NXdata
      @NX_class = NXdata
      @signal = 'counts'
      @axes = 'tth'
      @tth_indices = 0
      counts:NX_INT64[4] = [1, 50, 1000, 5]
        @units = counts
        @axes = tth
      tth:NX_FLOAT64[4] = [10.0, 10.1, 10.199999999999999, 10.300000000000001]
        @units = degrees

Classes and Methods

spec2nexus.eznx.addAttributes(parent, **attr)[source]

add attributes to an h5py data item

Parameters:
  • parent (obj) – h5py parent object
  • attr (dict) – optional dictionary of attributes
spec2nexus.eznx.makeDataset(parent, name, data=None, **attr)[source]

create and write data to a dataset in the HDF5 file hierarchy

Any named parameters in the call to this method will be saved as attributes of the dataset.

Parameters:
  • parent (obj) – parent group
  • name (str) – valid NeXus dataset name
  • data (obj) – the information to be written
  • attr (dict) – optional dictionary of attributes
Returns:

h5py dataset object

create an external link from sourceFile, sourcePath to targetPath in hdf5FileObject

Parameters:
  • hdf5FileObject (obj) – open HDF5 file object
  • sourceFile (str) – file containing existing HDF5 object at sourcePath
  • sourcePath (str) – path to existing HDF5 object in sourceFile
  • targetPath (str) – full node path to be created in current open HDF5 file, such as /entry/data/data

Note

Since the object retrieved is in a different file, its “.file” and “.parent” properties will refer to objects in that file, not the file in which the link resides.

See:http://www.h5py.org/docs-1.3/guide/group.html#external-links

This routine is provided as a reminder how to do this simple operation.

spec2nexus.eznx.makeFile(filename, **attr)[source]

create and open an empty NeXus HDF5 file using h5py

Any named parameters in the call to this method will be saved as attributes of the root of the file. Note that **attr is a dictionary of named parameters.

Parameters:
  • filename (str) – valid file name
  • attr (dict) – optional dictionary of attributes
Returns:

h5py file object

spec2nexus.eznx.makeGroup(parent, name, nxclass, **attr)[source]

create a NeXus group

Any named parameters in the call to this method will be saved as attributes of the group. Note that **attr is a dictionary of named parameters.

Parameters:
  • parent (obj) – parent group
  • name (str) – valid NeXus group name
  • nxclass (str) – valid NeXus class name
  • attr (dict) – optional dictionary of attributes
Returns:

h5py group object

create an internal NeXus (hard) link in an HDF5 file

Parameters:
  • parent (obj) – parent group of source
  • sourceObject (obj) – existing HDF5 object
  • targetName (str) – HDF5 node path to be created, such as /entry/data/data
spec2nexus.eznx.openGroup(parent, name, nx_class, **attr)[source]

open or create the NeXus/HDF5 group, return the object

Parameters:
  • parent (obj) – h5py parent object
  • name (str) – valid NeXus group name to open or create
  • nxclass (str) – valid NeXus class name (base class or application definition)
  • attr (dict) – optional dictionary of attributes
spec2nexus.eznx.read_nexus_field(parent, dataset_name, astype=None)[source]

get a dataset from the HDF5 parent group

Parameters:
  • parent (obj) – h5py parent object
  • dataset_name (str) – name of the dataset (NeXus field) to be read
  • astype (obj) – option to return as different data type
spec2nexus.eznx.read_nexus_group_fields(parent, name, fields)[source]

return the fields in the NeXus group as a dict(name=dataset)

This routine provides a mass way to read a directed list of datasets (NeXus fields) in an HDF5 group.

Parameters:
  • parent (obj) – h5py parent object
  • name (str) – name of the group containing the fields
  • fields ([name]) – list of field names to be read
Returns:

dictionary of {name:dataset}

Raises:

KeyError – if a field is not found

spec2nexus.eznx.write_dataset(parent, name, data, **attr)[source]

write to the NeXus/HDF5 dataset, create it if necessary, return the object

Parameters:
  • parent (obj) – h5py parent object
  • name (str) – valid NeXus dataset name to write
  • data (obj) – the information to be written
  • attr (dict) – optional dictionary of attributes