Changeset 1801 for trunk/bindings/python/nxs
- Timestamp:
- 16/01/12 18:06:09 (4 months ago)
- File:
-
- 1 edited
-
trunk/bindings/python/nxs/tree.py (modified) (84 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/bindings/python/nxs/tree.py
r1571 r1801 3 3 4 4 """ 5 Tree view for NeXus files. 6 7 The `nexus.tree` routines provide a natural interface to NeXus datasets. 8 Entries in a group are referenced much like fields in a class are 9 referenced in python. Rather than following the directory model of 10 the `nexus.napi` interface, users are free to reference separate fields 11 in the dataset at the same time. Large datasets are not read until 12 they are needed, and may be read or written one slab at a time. 13 14 There are a number of functions which operate on files:: 15 16 import nexus 17 nxfile = nexus.load('file.nxs') # loads a structure from a file 18 nexus.save('copy.nxs', tree) # saves a structure to a file 19 nexus.tree('copy.nxs') # display the contents of a file 20 21 The tree returned from load() has an entry for each group, field and 22 attribute. You can traverse the hierarchy using the names of the 23 groups. For example, tree.entry.instrument.detector.distance is an 24 example of a field containing the distance to each pixel in the 25 detector. Entries can also be referenced by NXclass name, such as 26 tree.NXentry[0].instrument. Since there may be multiple entries of the 27 same NXclass, the NXclass attribute returns a possibly empty list. 28 29 Properties of the entry in the tree are referenced by nx attributes. 30 Depending on the node type, different nx attributes may be available. 31 32 Nodes (class NXnode) have attributes shared by both groups and fields:: 33 * nxname node name 34 * nxclass node class for groups, 'SDS' for fields 35 * nxgroup group containing the entry, or None for the root 36 * nxattrs dictionary of NeXus attributes for the node 5 NeXus data as Python trees 6 ========================== 7 The `nexus.tree` modules are designed to accomplish two goals: 8 9 1. To provide convenient access to existing data contained in NeXus files. 10 2. To enable new NeXus data to be created and manipulated interactively. 11 12 These goals are achieved by mapping hierarchical NeXus data structures directly 13 into python objects, which either represent NeXus groups or NeXus fields. 14 Entries in a group are referenced much like fields in a class are referenced in 15 python. The entire data hierarchy can be referenced at any time, whether the 16 NeXus data has been loaded in from an existing NeXus file or created dynamically 17 within the python session. This provides a much more natural scripting interface 18 to NeXus data than the directory model of the `nexus.napi` interface. 19 20 Example 1: Loading a NeXus file 21 ------------------------------- 22 The following commands loads NeXus data from a file, displays (some of) the 23 contents as a tree, and then accesses individual data items. 24 25 >>> from nexpy.api import nexus as nx 26 >>> a=nx.load('sns/data/ARCS_7326.nxs') 27 >>> a.tree 28 root:NXroot 29 @HDF5_Version = 1.8.2 30 @NeXus_version = 4.2.1 31 @file_name = ARCS_7326.nxs 32 @file_time = 2010-05-05T01:59:25-05:00 33 entry:NXentry 34 data:NXdata 35 data = float32(631x461x4x825) 36 @axes = rotation_angle:tilt_angle:sample_angle:time_of_flight 37 @signal = 1 38 rotation_angle = float32(632) 39 @units = degree 40 sample_angle = [ 210. 215. 220. 225. 230.] 41 @units = degree 42 tilt_angle = float32(462) 43 @units = degree 44 time_of_flight = float32(826) 45 @units = microsecond 46 run_number = 7326 47 sample:NXsample 48 pulse_time = 2854.94747365 49 @units = microsecond 50 . 51 . 52 . 53 >>> a.entry.run_number 54 NXfield(7326) 55 56 So the tree returned from load() has an entry for each group, field and 57 attribute. You can traverse the hierarchy using the names of the groups. For 58 example, tree.entry.instrument.detector.distance is an example of a field 59 containing the distance to each pixel in the detector. Entries can also be 60 referenced by NXclass name, such as tree.NXentry[0].instrument. Since there may 61 be multiple entries of the same NeXus class, the NXclass attribute returns a 62 (possibly empty) list. 63 64 The load() and save() functions are implemented using the class 65 `nexus.tree.NeXusTree`, a subclass of `nexus.napi.NeXus` which allows all the 66 usual API functions. 67 68 Example 2: Creating a NeXus file dynamically 69 -------------------------------------------- 70 The second example shows how to create NeXus data dynamically and saves it to a 71 file. The data are first created as Numpy arrays 72 73 >>> import numpy as np 74 >>> x=y=np.linspace(0,2*np.pi,101) 75 >>> X,Y=np.meshgrid(y,x) 76 >>> z=np.sin(X)*np.sin(Y) 77 78 Then a NeXus data groups are created and the data inserted to produce a 79 NeXus-compliant structure that can be saved to a file. 80 81 >>> root=nx.NXroot(NXentry()) 82 >>> root.tree 83 root:NXroot 84 entry:NXentry 85 >>> root.entry.data=nx.NXdata(z,[x,y]) 86 87 Additional metadata can be inserted before saving the data to a file. 88 89 >>> root.entry.sample=nx.NXsample() 90 >>> root.entry.sample.temperature = 40.0 91 >>> root.entry.sample.temperature.units = 'K' 92 >>> root.save('example.nxs') 93 94 NeXus Objects 95 ------------- 96 Properties of the entry in the tree are referenced by attributes that depend 97 on the object type, different nx attributes may be available. 98 99 Objects (class NXobject) have attributes shared by both groups and fields:: 100 * nxname object name 101 * nxclass object class for groups, 'NXfield' for fields 102 * nxgroup group containing the entry, or None for the root 103 * attrs dictionary of NeXus attributes for the object 37 104 38 105 Groups (class NXgroup) have attributes for accessing children:: 39 * nxentries dictionary of entries within the group 40 * nxcomponent('nxclass') return group entries of a particular class 41 * nxdir() print the list of entries in the group 42 * nxtree() print the list of entries and subentries in the group 43 * nxplot() plot signal and axes for the group, if available 44 45 Fields (class SDS) have attributes for accessing data: 46 * nxdims dimensions of data in the field 47 * nxtype data type 48 * nxdata data in the field 49 * nxdata_as data returned in particular units 50 * nxslab slab context for the field 51 52 Linked fields (class NXlink) have attributes for accessing the link:: 53 * nxlink reference to the linked field 54 55 Unknown fields (class Unknown) are groups with a name that doesn't 56 start with 'NX'. These groups are not loaded or saved. 106 * entries dictionary of entries within the group 107 * component('nxclass') return group entries of a particular class 108 * dir() print the list of entries in the group 109 * tree print the list of entries and subentries in the group 110 * plot() plot signal and axes for the group, if available 111 112 Fields (class NXfield) have attributes for accessing data: 113 * shape dimensions of data in the field 114 * dtype data type 115 * nxdata data in the field 116 117 Linked fields or groups (class NXlink) have attributes for accessing the link:: 118 * nxlink reference to the linked field or group 57 119 58 120 NeXus attributes (class NXattr) have a type and a value only:: 59 * nxtype attribute type 60 * nxdata attribute data 61 62 Data can be stored in the NeXus file in a variety of units, depending 63 on which facility is storing the file. This makes life difficult 64 for reduction and analysis programs which must know the units they 65 are working with. Our solution to this problem is to allow the reader 66 to retrieve data from the file in particular units. For example, if 67 detector distance is stored in the file using millimeters you can 68 retrieve them in meters using:: 69 entry.instrument.detector.distance.nxdata_as('m') 121 * dtype attribute type 122 * nxdata attribute data 123 124 There is a subclass of NXgroup for each group class defined by the NeXus standard, 125 so it is possible to create an NXgroup of NeXus class NXsample directly using: 126 127 >>> sample = NXsample() 128 129 The default group name will be the class name following the 'NX', so the above 130 group will have an nxname of 'sample'. However, this is overridden by the 131 attribute name when it is assigned as a group attribute, e.g., 132 133 >>> entry.sample1 = NXsample() 134 >>> entry.sample1.nxname 135 sample1 136 137 You can traverse the tree by component class instead of component name. Since 138 there may be multiple components of the same class in one group you will need to 139 specify which one to use. For example, 140 141 tree.NXentry[0].NXinstrument[0].NXdetector[0].distance 142 143 references the first detector of the first instrument of the first entry. 144 Unfortunately, there is no guarantee regarding the order of the entries, and it 145 may vary from call to call, so this is mainly useful in iterative searches. 146 147 148 Unit Conversion 149 --------------- 150 Data can be stored in the NeXus file in a variety of units, depending on which 151 facility is storing the file. This makes life difficult for reduction and 152 analysis programs which must know the units they are working with. Our solution 153 to this problem is to allow the reader to retrieve data from the file in 154 particular units. For example, if detector distance is stored in the file using 155 millimeters you can retrieve them in meters using:: 156 157 entry.instrument.detector.distance.convert('m') 158 70 159 See `nexus.unit` for more details on the unit formats supported. 71 160 72 The slab interface to field data works by opening the file handle 73 and keeping it open as long as the slab interface is needed. This 74 is done in python 2.5 using the with statement. Once the context 75 is entered, nxget() and nxput() methods on the node allow you to read 76 and write data a slab at a time. For example:: 161 Reading and Writing Slabs 162 ------------------------- 163 The slab interface to field data works by opening the file handle and keeping it 164 open as long as the slab interface is needed. This is done in python 2.5 using 165 the with statement. Once the context is entered, get() and put() methods on the 166 object allow you to read and write data a slab at a time. For example:: 77 167 78 168 # Read a Ni x Nj x Nk array one vector at a time 79 169 with root.NXentry[0].data.data as slab: 80 Ni,Nj,Nk = slab. nxdims170 Ni,Nj,Nk = slab.shape 81 171 size = [1,1,Nk] 82 172 for i in range(Ni): 83 173 for j in range(Nj): 84 value = slab. nxget([i,j,0],size)174 value = slab.get([i,j,0],size) 85 175 86 176 The equivalent can be done in Python 2.4 and lower using the context 87 177 functions __enter__ and __exit__:: 88 178 89 slab = data. nxslab.__enter__()179 slab = data.slab.__enter__() 90 180 ... do the slab functions ... 91 data. nxslab.__exit__()92 93 You can traverse the tree by component class instead of component name. 94 Since there may be multiple components of the same class in one group 95 you will need to specify which one to use. For example, 96 tree.NXentry[0].NXinstrument[0].NXdetector[0].distance references the 97 first detector of the first instrument of the first entry. Unfortunately, 98 the re is no guarantee regarding the order of the entries, and it may vary99 from call to call, so the above is of limited utility.100 101 The nxplot() method for groups uses matplotlib to plot the data. You102 can replace this with your own plotter by setting nexus.NXgroup._plotter103 to your own plotterclass. The plotter class has one method::181 data.slab.__exit__() 182 183 Plotting NeXus data 184 ------------------- 185 There is a plot() method for groups that automatically looks for 'signal' and 186 'axes' attributes within the group in order to determine what to plot. These are 187 defined by the 'nxsignal' and 'nxaxes' properties of the group. This means that 188 the method will determine whether the plot should be one- or two- dimensional. 189 For higher than two dimensions, only the top slice is plotted by default. 190 191 The plot() method uses matplotlib by default to plot the data. You can replace 192 this with your own plotter by setting nexus.NXgroup._plotter to your own plotter 193 class. The plotter class has one method:: 104 194 105 195 plot(signal, axes, entry, title) 106 196 107 where signal is the field containing the data, axes are the fields 108 listing the signal sample points, entry is file/path within the file 109 to the data group and title is the title of the NXentry, if available. 110 111 The load() and save() functions are implemented using the class 112 `nexus.tree.NeXusTree`, a subclass of `nexus.napi.NeXus` which allows 113 all the usual API functions. You can subclass NeXusTree with your 114 own version that defines, e.g., a NXmonitor() method to return an 115 NXmonitor object when an NXmonitor class is read. Your NXmonitor 116 class should probably be a subclass of NXgroup. 197 where signal is the field containing the data, axes are the fields listing the 198 signal sample points, entry is file/path within the file to the data group and 199 title is the title of the group or the parent NXentry, if available. 117 200 """ 118 __all__ = ['NeXusTree', 'SDS', 'NXgroup', 'NXattr', 119 'NXroot', 'NXentry', 'NXdata', 'NXmonitor', 'NXsample', 120 'NXinstrument', 'NXaperture', 'NXattenuator', 'NXbeam_stop', 121 'NXbending_magnet', 'NXcollimator', 'NXcrystal', 'NXdetector', 122 'NXdisk_chopper', 'NXfermi_chopper', 'NXfilter', 'NXflipper', 123 'NXguide', 'NXinsertion_device', 'NXmirror', 'NXmoderator', 124 'NXmonochromator', 'NXpolarizer', 'NXpositioner', 'NXsource', 125 'NXvelocity_selector', 'NXevent_data', 'NXuser', 'NXparameter', 126 'NXprocess', 'NXcharacterization', 'NXlog', 'NXnote', 'NXbeam', 127 'NXgeometry', 'NXtranslation', 'NXshape', 'NXorientation', 128 'NXenvironment', 'NXsensor', 129 'load', 'save', 'tree', 'centers'] 130 131 132 from copy import copy 201 202 __all__ = ['NeXusTree', 'NXobject', 'NXfield', 'NXgroup', 'NXattr', 203 'NX_MEMORY', 'setmemory', 'load', 'save', 'tree', 'centers', 204 'NXlink', 'NXlinkfield', 'NXlinkgroup', 'SDS', 'NXlinkdata'] 205 206 from copy import copy, deepcopy 133 207 134 208 import numpy as np 135 209 import napi 136 import unit137 210 from napi import NeXusError 138 211 212 #Memory in MB 213 NX_MEMORY = 500 214 215 #List of defined base classes (later added to __all__) 216 _nxclasses = ['NXroot', 'NXentry', 'NXsubentry', 'NXdata', 'NXmonitor', 217 'NXlog', 'NXsample', 'NXinstrument', 'NXaperture', 'NXattenuator', 218 'NXbeam', 'NXbeam_stop', 'NXbending_magnet', 'NXcharacterization', 219 'NXcollection', 'NXcollimator', 'NXcrystal', 'NXdetector', 220 'NXdisk_chopper', 'NXenvironment', 'NXevent_data', 221 'NXfermi_chopper', 'NXfilter', 'NXflipper', 'NXgeometry', 222 'NXguide', 'NXinsertion_device', 'NXmirror', 'NXmoderator', 223 'NXmonochromator', 'NXnote', 'NXorientation', 'NXparameter', 224 'NXpolarizer', 'NXpositioner', 'NXprocess', 'NXsensor', 'NXshape', 225 'NXsource', 'NXtranslation', 'NXuser', 'NXvelocity_selector', 'NXtree'] 226 139 227 np.set_printoptions(threshold=5) 140 228 141 229 class NeXusTree(napi.NeXus): 230 142 231 """ 143 232 Structure-based interface to the NeXus file API. … … 167 256 the file closed again. open/close are available for when we want to 168 257 read/write slabs without the overhead of moving the file cursor each time. 169 The NXdata nodes in the returned tree hold the nodevalues.258 The NXdata objects in the returned tree hold the object values. 170 259 171 260 Subclasses can provide methods for individual NeXus classes such 172 261 as NXbeam or NXdata. Brave users can also specialize NXgroup, 173 NXattr, SDS and NXlink methods. 174 """ 262 NXattr, NXfield and NXlink methods. 263 """ 264 175 265 def readfile(self): 176 266 """ 177 Read the nexus file structure from the file. Large datasets 178 are not read until they are needed. 179 180 Returns a tree of NXgroup, SDS and NXlink nodes. 267 Read the NeXus file structure from the file and return a tree of NXobjects. 268 269 Large datasets are not read until they are needed. 181 270 """ 182 271 self.open() … … 184 273 root = self._readgroup() 185 274 self.close() 186 root. nxgroup = None187 # Resolve links (not necessary now that nxlink is set as a property)275 root._group = None 276 # Resolve links (not necessary now that link is set as a property) 188 277 #self._readlinks(root, root) 278 root._file = self 189 279 return root 190 280 191 281 def writefile(self, tree): 192 282 """ 193 Write the nexus file structure to the file. The file is assumed to 194 start empty. 195 196 Updating individual nodes can be done using the napi interface, with 197 nx.handle as the nexus file handle. 283 Write the NeXus file structure to a file. 284 285 The file is assumed to start empty. Updating individual objects can be 286 done using the napi interface, with nx.handle as the nexus file handle. 198 287 """ 199 288 self.open() 200 289 links = [] 201 # Root node is special --- only write its children. 202 # TODO: maybe want to write root node attributes? 203 for entry in tree.nxentries.values(): 290 for entry in tree.entries.values(): 204 291 links += self._writegroup(entry, path="") 205 292 self._writelinks(links) … … 208 295 def readpath(self, path): 209 296 """ 210 Re adthe data on a particular file path.297 Return the data on a particular file path. 211 298 212 299 Returns a numpy array containing the data, a python scalar, or a … … 222 309 def _readdata(self, name): 223 310 """ 224 Read a data node, returning SDS or NXlink depending on the 225 nature of the node. 311 Read a data object and return it as an NXfield or NXlink. 226 312 """ 227 313 # Finally some data, but don't read it if it is big 228 314 # Instead record the location, type and size 229 315 self.opendata(name) 316 attrs={} 230 317 attrs = self.getattrs() 231 if 'target' in attrs and attrs['target'] .nxdata!= self.path:318 if 'target' in attrs and attrs['target'] != self.path: 232 319 # This is a linked dataset; don't try to load it. 233 320 #print "read link %s->%s"%(path,attrs['target'].nxdata) 234 data = NXlink data(target=attrs['target'].nxdata, name=name)321 data = NXlinkfield(target=attrs['target'], name=name) 235 322 else: 236 323 dims,type = self.getinfo() … … 243 330 else: 244 331 value = None 245 data = self.SDS(value=value,name=name,dtype=type,shape=dims, 246 attrs=attrs,file=self,path=self.path) 332 data = NXfield(value=value,name=name,dtype=type,shape=dims,attrs=attrs) 247 333 self.closedata() 248 334 return data … … 254 340 def _readchildren(self,n): 255 341 children = {} 256 for dummyin range(n):342 for _item in range(n): 257 343 name,nxclass = self.getnextentry() 258 #print "name,class,path",name,nxclass,self.path259 344 if nxclass in self._skipgroups: 260 345 pass # Skip known bogus classes 261 elif nxclass == 'SDS': 346 elif nxclass == 'SDS': # NXgetnextentry returns 'SDS' as the class for NXfields 262 347 children[name] = self._readdata(name) 263 elif nxclass.startswith('NX'): 264 self.opengroup(name,nxclass) 265 children[name] = self._readgroup() 266 self.closegroup() 267 else: # Bad entry; flag it but don't do anything 268 # children[name] = self.Unknown(nxname=name,nxclass=nxclass) 348 else: 269 349 self.opengroup(name,nxclass) 270 350 children[name] = self._readgroup() … … 274 354 def _readgroup(self): 275 355 """ 276 Read the currently open group and all subgroups. 277 """ 278 # TODO: does it make sense to read without recursing? 279 # TODO: can we specify which NXclasses we are interested 280 # in and skip those of different classes? 356 Read the currently open group and return it as an NXgroup. 357 """ 281 358 n,name,nxclass = self.getgroupinfo() 282 attrs = self.getattrs() 283 if 'target' in attrs and attrs['target'].nxdata != self.path: 359 attrs = {} 360 attrs = self.getattrs() 361 if 'target' in attrs and attrs['target'] != self.path: 284 362 # This is a linked group; don't try to load it. 285 #print "read group link %s->%s"%(attrs['target'].nxdata,self.path) 286 group = self.NXlinkgroup(target=attrs['target'].nxdata, name=name) 287 else: 288 #print "read group",nxclass,"from",self.path 363 group = self.NXlinkgroup(target=attrs['target'], name=name) 364 else: 289 365 children = self._readchildren(n) 290 366 # If we are subclassed with a handler for the particular 291 367 # NXentry class name use that constructor for the group 292 368 # rather than the generic NXgroup class. 293 if hasattr(self,nxclass): 294 factory = getattr(self,nxclass) 295 #print 'factory', type(self), type(nxclass), type(factory) 296 else: 297 factory = self.NXgroup 298 group = factory(nxclass=nxclass,nxname=name,attrs=attrs,entries=children) 369 # if hasattr(self,nxclass): 370 # factory = getattr(self,nxclass) 371 # else: 372 # factory = self.NXgroup 373 group = NXgroup(nxclass=nxclass,name=name,attrs=attrs,entries=children) 299 374 # Build chain back structure 300 for nodein children.values():301 node.nxgroup = group375 for obj in children.values(): 376 obj._group = group 302 377 return group 303 378 304 379 def _readlinks(self, root, group): 305 380 """ 306 Convert linked nodes into direct references.307 """ 308 for entry in group. nxentries.values():309 if isinstance(entry, NXlink data) or isinstance(entry, NXlinkgroup):381 Convert linked objects into direct references. 382 """ 383 for entry in group.entries.values(): 384 if isinstance(entry, NXlink): 310 385 link = root 311 386 try: … … 318 393 self._readlinks(root, entry) 319 394 320 # Allow subclasses to override321 def NXattr(self, *args, **kw): return NXattr(*args, **kw)322 def SDS(self, *args, **kw): return SDS(*args, **kw)323 def NXgroup(self,*args,**kw): return NXgroup(*args, **kw)324 def NXroot(self,*args,**kw): return NXroot(*args, **kw)325 def NXentry(self,*args,**kw): return NXentry(*args, **kw)326 def NXdata(self,*args,**kw): return NXdata(*args, **kw)327 def NXmonitor(self,*args,**kw): return NXmonitor(*args, **kw)328 def NXsample(self,*args,**kw): return NXsample(*args, **kw)329 def NXinstrument(self,*args,**kw): return NXinstrument(*args, **kw)330 def NXaperture(self,*args,**kw): return NXaperture(*args,**kw)331 def NXattenuator(self,*args,**kw): return NXattenuator(*args,**kw)332 def NXbeam_stop(self,*args,**kw): return NXbeam_stop(*args,**kw)333 def NXbending_magnet(self,*args,**kw): return NXbending_magnet(*args,**kw)334 def NXcollimator(self,*args,**kw): return NXcollimator(*args,**kw)335 def NXcrystal(self,*args,**kw): return NXcrystal(*args,**kw)336 def NXdetector(self,*args,**kw): return NXdetector(*args,**kw)337 def NXdisk_chopper(self,*args,**kw): return NXdisk_chopper(*args,**kw)338 def NXfermi_chopper(self,*args,**kw): return NXfermi_chopper(*args,**kw)339 def NXfilter(self,*args,**kw): return NXfilter(*args,**kw)340 def NXflipper(self,*args,**kw): return NXflipper(*args,**kw)341 def NXguide(self,*args,**kw): return NXguide(*args,**kw)342 def NXinsertion_device(self,*args,**kw): return NXinsertion_device(*args,**kw)343 def NXmirror(self,*args,**kw): return NXmirror(*args,**kw)344 def NXmoderator(self,*args,**kw): return NXmoderator(*args,**kw)345 def NXmonochromator(self,*args,**kw): return NXmonochromator(*args,**kw)346 def NXpolarizer(self,*args,**kw): return NXpolarizer(*args,**kw)347 def NXpositioner(self,*args,**kw): return NXpositioner(*args,**kw)348 def NXsource(self,*args,**kw): return NXsource(*args,**kw)349 def NXvelocity_selector(self,*args,**kw): return NXvelocity_selector(*args,**kw)350 def NXevent_data(self,*args,**kw): return NXevent_data(*args,**kw)351 def NXuser(self,*args,**kw): return NXuser(*args,**kw)352 def NXprocess(self,*args,**kw): return NXprocess(*args,**kw)353 def NXparameter(self,*args,**kw): return NXparameter(*args,**kw)354 def NXcharacterization(self,*args,**kw): return NXcharacterization(*args,**kw)355 def NXlog(self,*args,**kw): return NXlog(*args,**kw)356 def NXnote(self,*args,**kw): return NXnote(*args,**kw)357 def NXbeam(self,*args,**kw): return NXbeam(*args,**kw)358 def NXgeometry(self,*args,**kw): return NXgeometry(*args,**kw)359 def NXtranslation(self,*args,**kw): return NXtranslation(*args,**kw)360 def NXshape(self,*args,**kw): return NXshape(*args,**kw)361 def NXorientation(self,*args,**kw): return NXorientation(*args,**kw)362 def NXenvironment(self,*args,**kw): return NXenvironment(*args,**kw)363 def NXsensor(self,*args,**kw): return NXsensor(*args,**kw)364 def NXlink(self, *args, **kw): return NXlink(*args, **kw)365 def NXlinkdata(self, *args, **kw): return NXlinkdata(*args, **kw)366 def NXlinkgroup(self, *args, **kw): return NXlinkgroup(*args, **kw)367 def Unknown(self, *args, **kw): return Unknown(*args, **kw)368 369 395 def _writeattrs(self, attrs): 370 396 """ 371 Return the attributes for the currently open group/data or for 372 the file if no group or data object is open. 397 Return the attributes for the currently open group/data. 398 399 If no group or data object is open, the file attributes are returned. 373 400 """ 374 401 for name,pair in attrs.iteritems(): 375 #print "write attrs",name,pair.nxtype,pair.nxdata 376 self.putattr(name,pair.nxdata,pair.nxtype) 402 self.putattr(name,pair.nxdata,pair.dtype) 377 403 378 404 def _writedata(self, data, path): 379 405 """ 380 Write the given data node.406 Write the given data to a file. 381 407 382 408 NXlinks cannot be written until the linked group is created, so … … 386 412 387 413 path = path + "/" + data.nxname 388 #print 'write data',path 414 shape = data.shape 415 if data.shape == (): shape = (1,) 389 416 390 417 # If the data is linked then … … 394 421 # Finally some data, but don't read it if it is big 395 422 # Instead record the location, type and size 396 #print "creating data",child.nxname,child.nxdims,child.nxtype397 423 #If the array size is too large, their product needs a long integer 398 if np.prod( data.nxdims) > 10000 or np.prod(data.nxdims) < 0:424 if np.prod(shape) > 10000 or np.prod(shape) < 0: 399 425 # Compress the fastest moving dimension of large datasets 400 slab_dims = np.ones(len(data.nxdims),'i') 401 slab_dims[-1] = data.nxdims[-1] 402 self.compmakedata(data.nxname, data.nxtype, data.nxdims, 403 'lzw', slab_dims) 426 slab_dims = np.ones(len(shape),'i') 427 if shape[-1] < 100000: 428 slab_dims[-1] = shape[-1] 429 else: 430 slab_dims[-1] = 100000 431 self.compmakedata(data.nxname, data.dtype, shape, 'lzw', slab_dims) 404 432 else: 405 433 # Don't use compression for small datasets 406 self.makedata(data.nxname, data.nxtype, data.nxdims) 434 try: 435 self.makedata(data.nxname, data.dtype, shape) 436 except StandardError,errortype: 437 print "Error in tree, makedata: ",errortype 438 407 439 self.opendata(data.nxname) 408 self._writeattrs(data. nxattrs)440 self._writeattrs(data.attrs) 409 441 value = data.nxdata 410 442 if value is not None: 411 self.putdata(data.nxdata) 443 self.putdata(data.nxdata) 412 444 self.closedata() 413 445 return [] … … 422 454 """ 423 455 path = path + "/" + group.nxname 424 #print 'write group',path425 456 426 457 links = [] 427 458 self.makegroup(group.nxname, group.nxclass) 428 459 self.opengroup(group.nxname, group.nxclass) 429 self._writeattrs(group. nxattrs)460 self._writeattrs(group.attrs) 430 461 if hasattr(group, '_target'): 431 462 links += [(path, group._target)] 432 for child in group. nxentries.values():433 if child.nxclass == ' SDS':463 for child in group.entries.values(): 464 if child.nxclass == 'NXfield': 434 465 links += self._writedata(child,path) 435 466 elif hasattr(child,'_target'): … … 442 473 def _writelinks(self, links): 443 474 """ 444 Create links within the NeXus file as indicated by the set of pairs 445 returned by writegroup. 475 Create links within the NeXus file. 476 477 THese are defined by the set of pairs returned by _writegroup. 446 478 """ 447 479 gid = {} … … 472 504 self.makelink(gid[target]) 473 505 474 _pythontype={type(int()):'int32', type(long()):'int64', 475 type(float()):'float32', type(str()):'char'} 476 477 def _gettype(value): 478 if isinstance(value, np.generic) or isinstance(value, np.ndarray): 479 nxtype = value.dtype.name 480 nxdims = max(list(value.shape),[1]) 481 else: 482 try: 483 nxtype = _pythontype[type(value)] 484 #print "In api.tree._gettype(value), _pythontype[type(value)]: " + nxtype 485 if nxtype == 'char': 486 nxdims = [len(value)] 487 else: 488 nxdims = [1] 489 except KeyError: 490 nxtype = '' 491 nxdims = [1] 492 return nxtype, nxdims 493 494 def _settype(value, nxtype): 495 if nxtype == _gettype(value)[0]: 496 return value 497 elif nxtype == 'char': 498 return str(value) 499 else: 500 return value.astype(nxtype) 501 502 503 def getClass(classname, modulename="tree"): 504 return getattr(__import__(modulename, globals(), locals(), [classname]), classname) 505 506 def getAxes(axes): 507 """ 508 Parse the 'axes' attribute for the axis names. 506 507 def _readaxes(axes): 508 """ 509 Return a list of axis names stored in the 'axes' attribute. 509 510 510 511 The delimiter separating each axis can be white space, a comma, or a colon. … … 512 513 import re 513 514 sep=re.compile('[\[]*(\s*,*:*)+[\]]*') 514 return filter(lambda x: len(x)>0, sep.split(axes.nxdata)) 515 516 def getRoot(node): 517 if node.nxgroup == None: 518 return None 519 elif node.nxgroup.nxclass == "NXroot": 520 return node.nxgroup 521 else: 522 return getRoot(node.nxgroup) 515 return filter(lambda x: len(x)>0, sep.split(axes)) 516 517 518 class AttrDict(dict): 519 520 """ 521 A dictionary class to assign all attributes to the NXattr class. 522 """ 523 524 def __setitem__(self, key, value): 525 if isinstance(value, NXattr): 526 dict.__setitem__(self, key, value) 527 else: 528 dict.__setitem__(self, key, NXattr(value)) 523 529 524 530 525 531 class NXattr(object): 526 """ 527 Attributes need to keep track of nxtype as well as attribute value. 528 """ 532 533 """ 534 Class for NeXus attributes of a NXfield or NXgroup object. 535 536 This class is only used for NeXus attributes that are stored in a 537 NeXus file and helps to distinguish them from Python attributes. 538 There are two Python attributes for each NeXus attribute. 539 540 Python Attributes 541 ----------------- 542 nxdata : string, Numpy scalar, or Numpy ndarray 543 The value of the NeXus attribute. 544 dtype : string 545 The data type of the NeXus attribute. This is set to 'char' for 546 a string attribute or the string of the corresponding Numpy data type 547 for a numeric attribute. 548 549 NeXus Attributes 550 ---------------- 551 NeXus attributes are stored in the 'attrs' dictionary of the parent object, 552 NXfield or NXgroup, but can often be referenced or assigned using the 553 attribute name as if it were an object attribute. 554 555 For example, after assigning the NXfield, the following three attribute 556 assignments are all equivalent:: 557 558 >>> entry.sample.temperature = NXfield(40.0) 559 >>> entry.sample.temperature.attrs['units'] = 'K' 560 >>> entry.sample.temperature.units = NXattr('K') 561 >>> entry.sample.temperature.units = 'K' 562 563 The third version above is only allowed for NXfield attributes and is 564 not allowed if the attribute has the same name as one of the following 565 internally defined attributes, i.e., 566 567 ['entries', 'attrs', 'dtype','shape'] 568 569 or if the attribute name begins with 'nx' or '_'. It is only possible to 570 reference attributes with one of the proscribed names using the 'attrs' 571 dictionary. 572 573 """ 574 529 575 def __init__(self,value=None,dtype=''): 530 576 if isinstance(value, NXattr): 531 self. nxdata,self.nxtype = value.nxdata,value.nxtype577 self._data,self._dtype = value.nxdata,value.dtype 532 578 elif dtype: 533 self.nxdata,self.nxtype = value,dtype 534 else: 535 self.nxdata,self.nxtype = value,'char' 536 if value: 537 if isinstance(value, NXnode): 538 raise NeXusError, "A data attribute cannot be an SDS or NeXus group" 539 if isinstance(value, np.generic) or isinstance(value, np.ndarray): 540 self.nxtype = value.dtype.name 579 if dtype in np.typeDict: 580 self._data,self._dtype = np.__dict__[dtype](value),dtype 581 elif dtype == 'char': 582 self._data,self._dtype = str(value),dtype 583 else: 584 raise NeXusError, "Invalid data type" 585 else: 586 if isinstance(value, str): 587 self._data,self._dtype = str(value), 'char' 588 elif value is not None: 589 if isinstance(value, NXobject): 590 raise NeXusError, "A data attribute cannot be a NXfield or NXgroup" 541 591 else: 542 try: 543 self.nxtype = _pythontype[type(value)] 544 except KeyError: 545 pass 592 self._data = np.array(value) 593 self._dtype = self._data.dtype.name 594 if self._data.size == 1: 595 self._data = np.__dict__[self._dtype](self._data) 596 else: 597 self._data,self._dtype = None, 'char' 546 598 547 599 def __str__(self): … … 549 601 550 602 def __repr__(self): 551 if s elf.nxtype== 'char':552 return "NXattr('%s' ,'%s')"%(self.nxdata,self.nxtype)553 else: 554 return "NXattr(%s ,'%s')"%(self.nxdata,self.nxtype)603 if str(self.dtype) == 'char': 604 return "NXattr('%s')"%self.nxdata 605 else: 606 return "NXattr(%s)"%self.nxdata 555 607 556 608 def __eq__(self, other): … … 563 615 return self.nxdata == other 564 616 565 566 class NXnode(object): 617 def _getdata(self): 618 """ 619 Return the attribute value. 620 """ 621 return self._data 622 623 def _getdtype(self): 624 return self._dtype 625 626 nxdata = property(_getdata,doc="The attribute values") 627 dtype = property(_getdtype, "Data type of NeXus attribute") 628 629 _npattrs = filter(lambda x: not x.startswith('_'), np.ndarray.__dict__.keys()) 630 631 class NXobject(object): 632 567 633 """ 568 634 Abstract base class for elements in NeXus files. 569 635 570 The node has a subclass of SDS (Scientific Data Set), NXgroup, or one571 of the NXgroup subclasses. Child nodes should be accessible directly as572 object attributes. Constructors for NXnode objects are defined by either573 the SDS orNXgroup classes.574 575 Attributes576 ---------- 636 The object has a subclass of NXfield, NXgroup, or one of the NXgroup 637 subclasses. Child nodes should be accessible directly as object attributes. 638 Constructors for NXobject objects are defined by either the NXfield or 639 NXgroup classes. 640 641 Python Attributes 642 ----------------- 577 643 nxclass : string 578 The class of the NX node. NXnodes can have class SDS, NXgroup,579 or one of the NXgroup subclasses.644 The class of the NXobject. NXobjects can have class NXfield, NXgroup, or 645 be one of the NXgroup subclasses. 580 646 nxname : string 581 The name of the NXnode. 582 nxgroup : NXnode 583 The parent NXgroup, if the node is defined as the attribute of parent 584 node. 585 nxentries : list 586 A list of all the NeXus objects contained within an NXgroup. This list 587 excludes all node attributes whose names begin with 'nx' or '_'. 588 nxattrs : list 589 A list of all the NeXus attributes, i.e., attribute with class NXattr. 647 The name of the NXobject. Since it is possible to reference the same 648 Python object multiple times, this is not necessarily the same as the 649 object name. However, if the object is part of a NeXus tree, this will 650 be the attribute name within the tree. 651 nxgroup : NXgroup 652 The parent group containing this object within a NeXus tree. If the 653 object is not part of any NeXus tree, it will be set to None. 590 654 nxpath : string 591 The path to this nodewith respect to the root of the NeXus tree. For655 The path to this object with respect to the root of the NeXus tree. For 592 656 NeXus data read from a file, this will be a group of class NXroot, but 593 657 if the NeXus tree was defined interactively, it can be any valid 594 658 NXgroup. 595 """ 596 nxclass = "unknown" 597 nxname = "unknown" 598 nxgroup = None 659 nxroot : NXgroup 660 The root object of the NeXus tree containing this object. For 661 NeXus data read from a file, this will be a group of class NXroot, but 662 if the NeXus tree was defined interactively, it can be any valid 663 NXgroup. 664 nxfile : NeXusTree 665 The file handle of the root object of the NeXus tree containing this 666 object. 667 filename : string 668 The file name of NeXus object's tree file handle. 669 attrs : dict 670 A dictionary of the NeXus object's attributes. 671 672 Methods 673 ------- 674 dir(self, attrs=False, recursive=False): 675 Print the group directory. 676 677 The directory is a list of NeXus objects within this group, either NeXus 678 groups or NXfield data. If 'attrs' is True, NXfield attributes are 679 displayed. If 'recursive' is True, the contents of child groups are also 680 displayed. 681 682 tree: 683 Print the object's tree. 684 685 It invokes the 'dir' method with both 'attrs' and 'recursive' 686 set to True. Note that this method is defined as a property attribute and 687 does not require parentheses. 688 689 save(self, filename, format='w5') 690 Save the NeXus group into a file 691 692 The object is wrapped in an NXroot group (with name 'root') and an 693 NXentry group (with name 'entry'), if necessary, in order to produce 694 a valid NeXus file. 695 696 """ 697 698 _class = "unknown" 699 _name = "unknown" 700 _group = None 701 _file = None 599 702 600 703 def __str__(self): … … 602 705 603 706 def __repr__(self): 604 return "NXnode('%s','%s')"%(self.nxclass,self.nxname) 605 606 def __setattr__(self, name, value): 607 if not name.startswith('nx') and not name.startswith('_'): 608 if not isinstance(value, NXnode): 609 value = SDS(value) 610 value.nxname=name 611 value.nxgroup=self.nxname 612 object.__setattr__(self, name, value) 613 707 return "NXobject('%s','%s')"%(self.nxclass,self.nxname) 708 614 709 def _setattrs(self, attrs): 615 for k,v in attrs.items(): 616 setattr(self, k, v) 617 618 def _attrs(self): 619 return dict([(k,v) 620 for k,v in self.__dict__.items() 621 if isinstance(v,NXattr)]) 622 623 def _entries(self): 624 return dict([(k,v) 625 for k,v in self.__dict__.items() 626 if isinstance(v,NXnode) and not k.startswith('nx') 627 and not k.startswith('_')]) 628 629 nxattrs = property(_attrs,doc="NeXus attributes for node") 630 nxentries = property(_entries,doc="NeXus nodes within group") 631 710 for k,v in attrs.items(): 711 self._attrs[k] = v 712 632 713 def _str_name(self,indent=0): 633 if self.nxclass == ' SDS':714 if self.nxclass == 'NXfield': 634 715 return " "*indent+self.nxname 635 716 else: … … 640 721 641 722 def _str_attrs(self,indent=0): 642 attrs = self.nxattrs 643 names = attrs.keys() 723 names = self.attrs.keys() 644 724 names.sort() 645 725 result = [] 646 726 for k in names: 647 result.append(" "*indent+"@%s = %s"%(k, attrs[k].nxdata))727 result.append(" "*indent+"@%s = %s"%(k,self.attrs[k].nxdata)) 648 728 return "\n".join(result) 649 729 650 730 def _str_tree(self,indent=0,attrs=False,recursive=False): 651 731 """ 652 Print current node and possibly subnodes. 653 """ 654 # Print node 732 Print current object and possibly children. 733 """ 655 734 result = [self._str_name(indent=indent)] 656 if attrs and self. nxattrs:735 if attrs and self.attrs: 657 736 result.append(self._str_attrs(indent=indent+2)) 658 737 # Print children 659 entries = self. nxentries738 entries = self.entries 660 739 if entries: 661 740 names = entries.keys() … … 670 749 result 671 750 return "\n".join(result) 751 752 def dir(self,attrs=False,recursive=False): 753 """ 754 Print the object directory. 755 756 The directory is a list of NeXus objects within this object, either 757 NeXus groups or NXfields. If 'attrs' is True, NXfield attributes are 758 displayed. If 'recursive' is True, the contents of child groups are 759 also displayed. 760 """ 761 print self._str_tree(attrs=attrs,recursive=recursive) 762 763 @property 764 def tree(self): 765 """ 766 Print the directory tree. 767 768 The tree contains all child objects of this object and their children. 769 It invokes the 'dir' method with both 'attrs' and 'recursive' set 770 to True. 771 """ 772 print self._str_tree(attrs=True,recursive=True) 773 774 def treestr(self, attrs=True): 775 """Return directory tree string""" 776 return self._str_tree(attrs=attrs,recursive=True) 777 778 def save(self, filename=None, format='w5'): 779 """ 780 Save the NeXus object to a data file. 781 782 An error is raised if the object is an NXroot group from an external file 783 that has been opened as readonly and no file name is specified. 784 785 The object is wrapped in an NXroot group (with name 'root') and an 786 NXentry group (with name 'entry'), if necessary, in order to produce 787 a valid NeXus file. 788 """ 789 if self.nxclass == "NXroot": 790 tree = self 791 if filename is None: 792 if self._file: 793 if self._file.mode == napi.ACC_READ: 794 raise NeXusError, "NeXus file is readonly" 795 else: 796 self._file.close() 797 filename = self._file.filename 798 elif filename: 799 if self.nxclass == "NXentry": 800 tree = NXroot(self) 801 else: 802 tree = NXroot(NXentry(self)) 803 804 if filename is None: 805 raise NeXusError, "No output file specified" 806 807 file = NeXusTree(filename, format) 808 file.writefile(tree) 809 file.close() 810 tree._file = file 811 tree._file.open() 812 tree._file.openpath('/') 813 tree._setattrs(tree._file.getattrs()) 814 tree._file.close() 815 return tree 816 817 def _getclass(self): 818 return self._class 819 820 def _getname(self): 821 return self._name 822 823 def _getgroup(self): 824 return self._group 672 825 673 826 def _getpath(self): 674 827 if self.nxgroup is None: 675 828 return "" 829 elif isinstance(self.nxgroup, NXroot): 830 return "/" + self.nxname 676 831 else: 677 832 return self.nxgroup._getpath()+"/"+self.nxname 678 833 679 def _get headnode(self):834 def _getroot(self): 680 835 if self.nxgroup is None: 681 836 return self 682 else: 683 return self.nxgroup._getheadnode() 684 685 nxpath = property(_getpath, "Path to NeXus node") 686 nxhead = property(_getheadnode, "Head node of this object's tree") 687 688 def nxdir(self,attrs=False,recursive=False): 689 """ 690 Print the node directory. 691 692 The directory is a list of NeXus objects within this node, either 693 NeXus groups or SDS data. If 'attrs' is True, SDS attributes are 694 displayed. If 'recursive' is True, the contents of child groups are 695 also displayed. 696 """ 697 print self._str_tree(attrs=attrs,recursive=recursive) 698 699 def nxtree(self,attrs=True): 700 """ 701 Print the directory tree. 702 703 The tree contains all child objects of this node and their children. 704 It invokes the 'nxdir' method with both 'attrs' and 'recursive' set 705 to True. 706 """ 707 print self._str_tree(attrs=attrs,recursive=True) 708 709 def nxtreestr(self, attrs=True): 710 """Return directory tree string""" 711 return self._str_tree(attrs=attrs,recursive=True) 712 713 def nxsave(self, filename, format='w5'): 714 """ 715 Save the NeXus node to a data file. 716 717 The object is wrapped in an NXroot group (with name 'root') and an 718 NXentry group (with name 'entry'), if necessary, in order to produce 719 a valid NeXus file. 720 """ 721 #print "nxsave() call in tree.py NXnode class" 722 if self.nxclass == "NXroot": 723 tree = self 724 elif self.nxclass == "NXentry": 725 tree = NXroot(self) 726 else: 727 tree = NXroot(NXentry(self)) 728 file = NeXusTree(filename, format) 729 file.writefile(tree) 730 file.close() 731 732 733 class SDS(NXnode): 734 """ 735 A NeXus data node (Scientific Data Set). 736 737 This is a subclass of NXnode to contain scalar, array, or string data 837 elif isinstance(self.nxgroup, NXroot): 838 return self.nxgroup 839 else: 840 return self.nxgroup._getroot() 841 842 def _getfile(self): 843 return self.nxroot._file 844 845 def _getfilename(self): 846 return self.nxroot._file.filename 847 848 def _getattrs(self): 849 return self._attrs 850 851 nxclass = property(_getclass, doc="Class of NeXus object") 852 nxname = property(_getname, doc="Name of NeXus object") 853 nxgroup = property(_getgroup, doc="Parent group of NeXus object") 854 nxpath = property(_getpath, doc="Path to NeXus object") 855 nxroot = property(_getroot, doc="Root group of NeXus object's tree") 856 nxfile = property(_getfile, doc="File handle of NeXus object's tree") 857 filename = property(_getfilename, doc="File name of NeXus object's tree") 858 attrs = property(_getattrs, doc="NeXus attributes for an object") 859 860 861 class NXfield(NXobject): 862 863 """ 864 A NeXus data field. 865 866 This is a subclass of NXobject that contains scalar, array, or string data 738 867 and associated NeXus attributes. 739 868 740 SDS(value=None, name='unknown', dtype='', shape=[], attrs={}, file=None,741 path=None, group=None, **attr)742 743 Parameters744 ---------- 869 NXfield(value=None, name='unknown', dtype='', shape=[], attrs={}, file=None, 870 path=None, group=None, **attr) 871 872 Input Parameters 873 ---------------- 745 874 value : scalar value, Numpy array, or string 746 The numerical or string value of the SDS, which is directly accessible747 a s the SDS attribute 'nxdata'.875 The numerical or string value of the NXfield, which is directly 876 accessible as the NXfield attribute 'nxdata'. 748 877 name : string 749 The name of the SDS, which is directly accessible as the SDS750 attribute 'n xname'. If the SDS is initialized as the attribute of751 a parent node, the name is automatically set to the name of this878 The name of the NXfield, which is directly accessible as the NXfield 879 attribute 'name'. If the NXfield is initialized as the attribute of a 880 parent object, the name is automatically set to the name of this 752 881 attribute. 753 882 dtype : string 754 The data type of the SDS value, which is directly accessible as the755 SDS attribute 'nxtype'. Valid types correspond to standard Numpy756 data types, using names defined by the NeXus API,883 The data type of the NXfield value, which is directly accessible as the 884 NXfield attribute 'dtype'. Valid input types correspond to standard 885 Numpy data types, using names defined by the NeXus API, 757 886 i.e., 'float32' 'float64' 758 887 'int8' 'int16' 'int32' 'int64' … … 762 891 by the data type of the 'value' parameter. 763 892 shape : list of ints 764 The dimensions of the SDS data, which is accessible as the SDS 765 attribute 'nxdims'. This corresponds to the shape of a Numpy array, 766 or the length of a string. The shape is [1] if the value is a scalar. 893 The dimensions of the NXfield data, which is accessible as the NXfield 894 attribute 'shape'. This corresponds to the shape of the Numpy array. 895 Scalars (numeric or string) are stored as Numpy zero-rank arrays, 896 for which shape=[]. 767 897 attrs : dict 768 A dictionary containing SDSattributes. The dictionary values should898 A dictionary containing NXfield attributes. The dictionary values should 769 899 all have class NXattr. 770 900 file : filename 771 The file from which the SDShas been read.901 The file from which the NXfield has been read. 772 902 path : string 773 The path to this nodewith respect to the root of the NeXus tree,903 The path to this object with respect to the root of the NeXus tree, 774 904 using the convention for unix file paths. 775 group : NXnode (SDS, NXgroup, or subclass of NXgroup) 776 The parent NeXus node, which is accessible as the SDS attribute 777 'nxgroup'. If the SDS is initialized as the attribute of 778 a parent node, the group is set to the parent node. 779 780 SDS attributes can also be set directly by keyword arguments, which are 781 converted to objects of class NXattr, e.g., 782 783 temperature = SDS(40.0, units='K') 784 785 Attributes 786 ---------- 787 nxclass : 'SDS' 788 The class of the NXnode. 905 group : NXgroup or subclass of NXgroup 906 The parent NeXus object. If the NXfield is initialized as the attribute 907 of a parent group, this attribute is automatically set to the parent group. 908 909 Python Attributes 910 ----------------- 911 nxclass : 'NXfield' 912 The class of the NXobject. 789 913 nxname : string 790 The name of the SDS. 791 nxtype : string 792 The data type of the SDS value. Valid values are given above. 793 nxdims : list of ints 794 The dimensions of the SDS data. This is equivalent to the shape of a 795 Numpy array. 796 nxattrs : dict 797 A dictionary of the SDS attributes, i.e., those with class NXattr 914 The name of the NXfield. Since it is possible to reference the same 915 Python object multiple times, this is not necessarily the same as the 916 object name. However, if the field is part of a NeXus tree, this will 917 be the attribute name within the tree. 918 nxgroup : NXgroup 919 The parent group containing this field within a NeXus tree. If the 920 field is not part of any NeXus tree, it will be set to None. 921 dtype : string or Numpy dtype 922 The data type of the NXfield value. If the NXfield has been initialized 923 but the data values have not been read in or defined, this is a string. 924 Otherwise, it is set to the equivalent Numpy dtype. 925 shape : list or tuple of ints 926 The dimensions of the NXfield data. If the NXfield has been initialized 927 but the data values have not been read in or defined, this is a list of 928 ints. Otherwise, it is set to the equivalent Numpy shape, which is a 929 tuple. Scalars (numeric or string) are stored as Numpy zero-rank arrays, 930 for which shape=(). 931 attrs : dict 932 A dictionary of all the NeXus attributes associated with the field. 933 These are objects with class NXattr. 798 934 nxdata : scalar, Numpy array or string 799 The data value of the SDS. This is normally initialized using the935 The data value of the NXfield. This is normally initialized using the 800 936 'value' parameter (see above). If the NeXus data is contained 801 in a file and the size of the SDSarray is too large to be stored937 in a file and the size of the NXfield array is too large to be stored 802 938 in memory, the value is not read in until this attribute is directly 803 939 accessed. Even then, if there is insufficient memory, a value of None 804 will be returned. In this case, the SDSarray should be read as a805 series of smaller slabs using ' nxget'.940 will be returned. In this case, the NXfield array should be read as a 941 series of smaller slabs using 'get'. 806 942 nxdata_as('units') : scalar value or Numpy array 807 If the SDS'units' attribute has been set, the data values, stored943 If the NXfield 'units' attribute has been set, the data values, stored 808 944 in 'nxdata', are returned after conversion to the specified units. 809 945 nxpath : string 810 The path to this nodewith respect to the root of the NeXus tree. For946 The path to this object with respect to the root of the NeXus tree. For 811 947 NeXus data read from a file, this will be a group of class NXroot, but 812 948 if the NeXus tree was defined interactively, it can be any valid 813 NXgroup. This is determined by recursively accessing the 'nxgroup' 814 attributes of the parent nodes. 815 949 NXgroup. 950 nxroot : NXgroup 951 The root object of the NeXus tree containing this object. For 952 NeXus data read from a file, this will be a group of class NXroot, but 953 if the NeXus tree was defined interactively, it can be any valid 954 NXgroup. 955 956 NeXus Attributes 957 ---------------- 958 NeXus attributes are stored in the 'attrs' dictionary of the NXfield, but 959 can usually be assigned or referenced as if they are Python attributes, as 960 long as the attribute name is not the same as one of those listed above. 961 This is to simplify typing in an interactive session and should not cause 962 any problems because there is no name clash with attributes so far defined 963 within the NeXus standard. When writing modules, it is recommended that the 964 attributes always be referenced using the 'attrs' dictionary if there is 965 any doubt. 966 967 a) Assigning a NeXus attribute 968 969 In the example below, after assigning the NXfield, the following three 970 NeXus attribute assignments are all equivalent: 971 972 >>> entry.sample.temperature = NXfield(40.0) 973 >>> entry.sample.temperature.attrs['units'] = 'K' 974 >>> entry.sample.temperature.units = NXattr('K') 975 >>> entry.sample.temperature.units = 'K' 976 977 b) Referencing a NeXus attribute 978 979 If the name of the NeXus attribute is not the same as any of the Python 980 attributes listed above, or one of the methods listed below, or any of the 981 attributes defined for Numpy arrays, they can be referenced as if they were 982 a Python attribute of the NXfield. However, it is only possible to reference 983 attributes with one of the proscribed names using the 'attrs' dictionary. 984 985 >>> entry.sample.temperature.tree = 10.0 986 >>> entry.sample.temperature.tree 987 temperature = 40.0 988 @tree = 10.0 989 @units = K 990 >>> entry.sample.temperature.attrs['tree'] 991 NXattr(10.0) 992 993 Numerical Operations on NXfields 994 -------------------------------- 995 NXfields usually consist of arrays of numeric data with associated 996 meta-data, the NeXus attributes. The exception is when they contain 997 character strings. This makes them similar to Numpy arrays, and this module 998 allows the use of NXfields in numerical operations in the same way as Numpy 999 ndarrays. NXfields are technically not a sub-class of the ndarray class, but 1000 most Numpy operations work on NXfields, returning either another NXfield or, 1001 in some cases, an ndarray that can easily be converted to an NXfield. 1002 1003 >>> x = NXfield((1.0,2.0,3.0,4.0)) 1004 >>> print x+1 1005 [ 2. 3. 4. 5.] 1006 >>> print 2*x 1007 [ 2. 4. 6. 8.] 1008 >>> print x/2 1009 [ 0.5 1. 1.5 2. ] 1010 >>> print x**2 1011 [ 1. 4. 9. 16.] 1012 >>> print x.reshape((2,2)) 1013 [[ 1. 2.] 1014 [ 3. 4.]] 1015 >>> y = NXfield((0.5,1.5,2.5,3.5)) 1016 >>> x+y 1017 NXfield(name=x,value=[ 1.5 3.5 5.5 7.5]) 1018 >>> x*y 1019 NXfield(name=x,value=[ 0.5 3. 7.5 14. ]) 1020 >>> (x+y).shape 1021 (4,) 1022 >>> (x+y).dtype 1023 dtype('float64') 1024 1025 All these operations return valid NXfield objects containing the same 1026 attributes as the first NXobject in the expression. The 'reshape' and 1027 'transpose' methods also return NXfield objects. 1028 1029 It is possible to use the standard slice syntax. 1030 1031 >>> x=NXfield(np.linspace(0,10,11)) 1032 >>> x 1033 NXfield([ 0. 1. 2. ..., 8. 9. 10.]) 1034 >>> x[2:5] 1035 NXfield([ 2. 3. 4.]) 1036 1037 In addition, it is possible to use floating point numbers as the slice 1038 indices. If one of the indices is not integer, both indices are used to 1039 extract elements in the array with values between the two index values. 1040 1041 >>> x=NXfield(np.linspace(0,100.,11)) 1042 >>> x 1043 NXfield([ 0. 10. 20. ..., 80. 90. 100.]) 1044 >>> x[20.:50.] 1045 NXfield([ 20. 30. 40. 50.]) 1046 1047 The standard Numpy ndarray attributes and methods will also work with 1048 NXfields, but will return scalars or Numpy arrays. 1049 1050 >>> x.size 1051 4 1052 >>> x.sum() 1053 10.0 1054 >>> x.max() 1055 4.0 1056 >>> x.mean() 1057 2.5 1058 >>> x.var() 1059 1.25 1060 >>> x.reshape((2,2)).sum(1) 1061 array([ 3., 7.]) 1062 1063 Finally, NXfields are cast as ndarrays for operations that require them. 1064 The returned value will be the same as for the equivalent ndarray 1065 operation, e.g., 1066 1067 >>> np.sin(x) 1068 array([ 0.84147098, 0.90929743, 0.14112001, -0.7568025 ]) 1069 >>> np.sqrt(x) 1070 array([ 1. , 1.41421356, 1.73205081, 2. ]) 1071 816 1072 Methods 817 1073 ------- 818 nxdir(self, attrs=False): 819 Print the SDS specification. 820 821 This outputs the name, dimensions and data type of the SDS. 822 If 'attrs' is True, SDS attributes are displayed. 823 824 nxtree(self, attrs=True): 825 Print the SDS and its attributes. 826 827 It invokes the 'nxdir' method with 'attrs' set to True. 828 829 nxsave(filename, format='w5') 830 Save the SDS into a file wrapped in a NXroot group and NXentry group 1074 dir(self, attrs=False): 1075 Print the NXfield specification. 1076 1077 This outputs the name, dimensions and data type of the NXfield. 1078 If 'attrs' is True, NXfield attributes are displayed. 1079 1080 tree: 1081 Print the NXfield's tree. 1082 1083 It invokes the 'dir' method with both 'attrs' and 'recursive' 1084 set to True. Note that this method is defined as a property attribute and 1085 does not require parentheses. 1086 1087 1088 save(self, filename, format='w5') 1089 Save the NXfield into a file wrapped in a NXroot group and NXentry group 831 1090 with default names. This is equivalent to 832 1091 833 >>> NXroot(NXentry( SDS(...))).nxsave(filename)1092 >>> NXroot(NXentry(NXfield(...))).save(filename) 834 1093 835 1094 Examples 836 1095 -------- 837 >>> x = SDS(np.linspace(0,2*np.pi,101), units='degree')1096 >>> x = NXfield(np.linspace(0,2*np.pi,101), units='degree') 838 1097 >>> phi = x.nxdata_as(units='radian') 839 >>> y = SDS(np.sin(phi))1098 >>> y = NXfield(np.sin(phi)) 840 1099 841 1100 # Read a Ni x Nj x Nk array one vector at a time 842 1101 >>> with root.NXentry[0].data.data as slab: 843 Ni,Nj,Nk = slab. nxdims1102 Ni,Nj,Nk = slab.shape 844 1103 size = [1,1,Nk] 845 1104 for i in range(Ni): 846 1105 for j in range(Nj): 847 value = slab.nxget([i,j,0],size) 848 849 """ 850 def __init__(self, value=None, name='unknown', dtype='', shape=(), attrs={}, 851 file=None, path=None, group=None, **attr): 1106 value = slab.get([i,j,0],size) 1107 1108 """ 1109 1110 def __init__(self, value=None, name='unknown', dtype=None, shape=(), attrs={}, group=None, 1111 **attr): 852 1112 if isinstance(value, list) or isinstance(value, tuple): 853 1113 value = np.array(value) 854 1114 self._value = value 855 self.nxclass = 'SDS' # Scientific Data Set 856 self.nxname = name 857 self.nxtype = '' 858 self.nxdims = list(shape) 859 #print "self.nxtype: " + str(self.nxtype) 860 if dtype: 861 self.nxtype = dtype 862 #print "self.nxtype: " + str(self.nxtype) 863 elif value is not None: 864 #print "Type declared in SDS.__init__(): " + str(_gettype(value)) 865 self.nxtype, self.nxdims = _gettype(value) 866 else: 867 self.nxtype = '' 868 self.nxgroup = group 1115 self._class = 'NXfield' 1116 self._name = name 1117 self._group = group 1118 self._dtype = dtype 1119 if dtype == 'char': 1120 self._dtype = 'char' 1121 elif dtype in np.typeDict: 1122 self._dtype = np.dtype(dtype) 1123 elif dtype: 1124 raise NeXusError, "Invalid data type: %s" % dtype 1125 self._shape = tuple(shape) 869 1126 # Append extra keywords to the attribute list 1127 self._attrs = AttrDict() 870 1128 for key in attr.keys(): 871 attrs[key] = NXattr(attr[key])1129 attrs[key] = attr[key] 872 1130 # Convert NeXus attributes to python attributes 873 1131 self._setattrs(attrs) 874 1132 if 'units' in attrs: 875 units = attrs['units'] .nxdata1133 units = attrs['units'] 876 1134 else: 877 1135 units = None 878 self._converter = unit.Converter(units)879 1136 self._incontext = False 880 self._file = file 881 self._path = path 882 for key in attrs.keys(): 883 del attrs[key] 1137 del attrs 1138 if value is not None and dtype == 'char': value = str(value) 1139 self._setdata(value) 884 1140 885 1141 def __repr__(self): 886 1142 if self._value is not None: 887 return "SDS(name=%s,value=%s)" % (self.nxname, self._str_value()) 888 else: 889 return "SDS(name='%s')" % self.nxname 890 1143 if str(self.dtype) == 'char': 1144 return "NXfield('%s')" % str(self) 1145 else: 1146 return "NXfield(%s)" % self._str_value() 1147 else: 1148 return "NXfield(dtype=%s,shape=%s)" % (self.dtype,self.shape) 1149 1150 def __getattr__(self, name): 1151 """ 1152 Enable standard numpy ndarray attributes if not otherwise defined. 1153 """ 1154 if name in _npattrs: 1155 return self.nxdata.__getattribute__(name) 1156 elif name in self.attrs: 1157 return self.attrs[name].nxdata 1158 raise KeyError(name+" not in "+self.nxname) 1159 891 1160 def __setattr__(self, name, value): 892 if name.startswith('nx') or name.startswith('_') or isinstance(value, NXattr): 1161 """ 1162 Add an attribute to the NXfield 'attrs' dictionary unless the attribute 1163 name starts with 'nx' or '_', or unless it is one of the standard Python 1164 attributes for the NXfield class. 1165 """ 1166 if name.startswith('_'): 893 1167 object.__setattr__(self, name, value) 894 else: 895 object.__setattr__(self, name, NXattr(value)) 896 897 def __len__(self): 898 """ 899 Return the length of the SDS data. 900 """ 901 return np.prod(self.nxdims) 902 903 def index(self, value, max=False): 904 """ 905 Return the index of the SDS nxdata array that is greater than or equal to the value. 906 907 If max, then return the index that is less than or equal to the value. 908 This should only be used on one-dimensional monotonically increasing arrays. 909 """ 910 if max: 911 return len(self.nxdata)-len(self.nxdata[self.nxdata>=value]) 912 else: 913 return len(self.nxdata[self.nxdata<value]) 1168 elif isinstance(value, NXattr): 1169 self._attrs[name] = value 1170 else: 1171 self._attrs[name] = NXattr(value) 914 1172 915 1173 def __getitem__(self, index): 916 1174 """ 917 Returns a slice from the SDS.918 919 In most cases, the slice values are applied to the SDSnxdata array920 and returned within an SDSobject with the same metadata. However,1175 Returns a slice from the NXfield. 1176 1177 In most cases, the slice values are applied to the NXfield nxdata array 1178 and returned within an NXfield object with the same metadata. However, 921 1179 if the array is one-dimensional and the index start and stop values 922 1180 are real, the nxdata array is returned with values between those limits. … … 931 1189 result = self.nxdata.__getitem__(index) 932 1190 else: 933 offset = np.zeros(len(self. nxdims),dtype=int)934 size = np.array(self. nxdims)1191 offset = np.zeros(len(self.shape),dtype=int) 1192 size = np.array(self.shape) 935 1193 if isinstance(index, int): 936 1194 offset[0] = index … … 948 1206 i = i + 1 949 1207 try: 950 result = self. nxget(offset, size)1208 result = self.get(offset, size) 951 1209 except ValueError: 952 1210 result = self.nxdata.__getitem__(index) 953 return SDS(result, name=self.nxname, attrs=self.nxattrs)1211 return NXfield(result, name=self.nxname, attrs=self.attrs) 954 1212 955 1213 def __setitem__(self, index, value): 956 1214 """ 957 Assign a slice to the SDS.1215 Assign a slice to the NXfield. 958 1216 """ 959 1217 if self._value is not None: 960 1218 self.nxdata[index] = value 961 1219 else: 962 raise NeXusError, "SDS dataspace not yet allocated" 1220 raise NeXusError, "NXfield dataspace not yet allocated" 1221 1222 def __deepcopy__(self, memo): 1223 dpcpy = self.__class__() 1224 memo[id(self)] = dpcpy 1225 dpcpy._value = copy(self._value) 1226 dpcpy._name = copy(self.nxname) 1227 dpcpy._dtype = copy(self.dtype) 1228 dpcpy._shape = copy(self.shape) 1229 for k, v in self.attrs.items(): 1230 dpcpy.attrs[k] = copy(v) 1231 return dpcpy 1232 1233 def __len__(self): 1234 """ 1235 Return the length of the NXfield data. 1236 """ 1237 return np.prod(self.shape) 1238 1239 def index(self, value, max=False): 1240 """ 1241 Return the index of the NXfield nxdata array that is greater than or equal to the value. 1242 1243 If max, then return the index that is less than or equal to the value. 1244 This should only be used on one-dimensional monotonically increasing arrays. 1245 """ 1246 if max: 1247 return len(self.nxdata)-len(self.nxdata[self.nxdata>=value]) 1248 else: 1249 return len(self.nxdata[self.nxdata<value]) 1250 1251 def __array__(self): 1252 """ 1253 Cast the NXfield as an array when it is expected by numpy 1254 """ 1255 return self.nxdata 963 1256 964 1257 def __eq__(self, other): 965 1258 """ 966 Return true if the values of the SDSare the same.967 """ 968 if isinstance(other, SDS):1259 Return true if the values of the NXfield are the same. 1260 """ 1261 if isinstance(other, NXfield): 969 1262 if isinstance(self.nxdata, np.ndarray) and isinstance(other.nxdata, np.ndarray): 970 1263 return all(self.nxdata == other.nxdata) … … 976 1269 def __ne__(self, other): 977 1270 """ 978 Return true if the values of the SDSare not the same.979 """ 980 if isinstance(other, SDS):1271 Return true if the values of the NXfield are not the same. 1272 """ 1273 if isinstance(other, NXfield): 981 1274 if isinstance(self.nxdata, np.ndarray) and isinstance(other.nxdata, np.ndarray): 982 1275 return any(self.nxdata != other.nxdata) … … 988 1281 def __add__(self, other): 989 1282 """ 990 Return the sum of the SDS and another SDSor number.1283 Return the sum of the NXfield and another NXfield or number. 991 1284 """ 992 1285 try: 993 if isinstance(other, SDS):994 return SDS(value=self.nxdata+other.nxdata, name=self.nxname,995 attrs=self.nxattrs)1286 if isinstance(other, NXfield): 1287 return NXfield(value=self.nxdata+other.nxdata, name=self.nxname, 1288 attrs=self.attrs) 996 1289 else: 997 return SDS(value=self.nxdata+other, name=self.nxname,998 attrs=self.nxattrs)1290 return NXfield(value=self.nxdata+other, name=self.nxname, 1291 attrs=self.attrs) 999 1292 except TypeError, message: 1000 1293 raise NeXusError, message … … 1002 1295 def __radd__(self, other): 1003 1296 """ 1004 Return the sum of the SDS and another SDSor number.1297 Return the sum of the NXfield and another NXfield or number. 1005 1298 1006 1299 This variant makes __add__ commutative. … … 1010 1303 def __sub__(self, other): 1011 1304 """ 1012 Return the SDS with the subtraction of another SDSor number.1305 Return the NXfield with the subtraction of another NXfield or number. 1013 1306 """ 1014 1307 try: 1015 if isinstance(other, SDS):1016 return SDS(value=self.nxdata-other.nxdata, name=self.nxname,1017 attrs=self.nxattrs)1308 if isinstance(other, NXfield): 1309 return NXfield(value=self.nxdata-other.nxdata, name=self.nxname, 1310 attrs=self.attrs) 1018 1311 else: 1019 return SDS(value=self.nxdata-other, name=self.nxname,1020 attrs=self.nxattrs)1312 return NXfield(value=self.nxdata-other, name=self.nxname, 1313 attrs=self.attrs) 1021 1314 except TypeError, message: 1022 1315 raise NeXusError, message … … 1024 1317 def __mul__(self, other): 1025 1318 """ 1026 Return the product of the SDS and another SDSor number.1319 Return the product of the NXfield and another NXfield or number. 1027 1320 """ 1028 1321 try: 1029 if isinstance(other, SDS):1030 return SDS(value=self.nxdata*other.nxdata, name=self.nxname,1031 attrs=self.nxattrs)1322 if isinstance(other, NXfield): 1323 return NXfield(value=self.nxdata*other.nxdata, name=self.nxname, 1324 attrs=self.attrs) 1032 1325 else: 1033 return SDS(value=self.nxdata*other, name=self.nxname,1034 attrs=self.nxattrs)1326 return NXfield(value=self.nxdata*other, name=self.nxname, 1327 attrs=self.attrs) 1035 1328 except TypeError, message: 1036 1329 raise NeXusError, message … … 1038 1331 def __rmul__(self, other): 1039 1332 """ 1040 Return the product of the SDS and another SDSor number.1333 Return the product of the NXfield and another NXfield or number. 1041 1334 1042 1335 This variant makes __mul__ commutative. … … 1046 1339 def __div__(self, other): 1047 1340 """ 1048 Return the SDS divided by another SDSor number.1341 Return the NXfield divided by another NXfield or number. 1049 1342 """ 1050 1343 try: 1051 if isinstance(other, SDS):1052 return SDS(value=self.nxdata/other.nxdata, name=self.nxname,1053 attrs=self.nxattrs)1344 if isinstance(other, NXfield): 1345 return NXfield(value=self.nxdata/other.nxdata, name=self.nxname, 1346 attrs=self.attrs) 1054 1347 else: 1055 return SDS(value=self.nxdata/other, name=self.nxname,1056 attrs=self.nxattrs)1348 return NXfield(value=self.nxdata/other, name=self.nxname, 1349 attrs=self.attrs) 1057 1350 except TypeError, message: 1058 1351 raise NeXusError, message … … 1060 1353 def __rdiv__(self, other): 1061 1354 """ 1062 Return the inverse of the SDS divided by another SDSor number.1355 Return the inverse of the NXfield divided by another NXfield or number. 1063 1356 """ 1064 1357 try: 1065 if isinstance(other, SDS):1066 return SDS(value=other.nxdata/self.nxdata, name=self.nxname,1067 attrs=self.nxattrs)1358 if isinstance(other, NXfield): 1359 return NXfield(value=other.nxdata/self.nxdata, name=self.nxname, 1360 attrs=self.attrs) 1068 1361 else: 1069 return SDS(value=other/self.nxdata, name=self.nxname,1070 attrs=self.nxattrs)1362 return NXfield(value=other/self.nxdata, name=self.nxname, 1363 attrs=self.attrs) 1071 1364 except TypeError, message: 1072 1365 raise NeXusError, message 1073 1366 1074 def nxreshape(self, shape): 1075 """ 1076 Returns the SDS with the defined shape 1077 """ 1078 self.nxdims = list(shape) 1367 def __pow__(self, power): 1368 """ 1369 Return the NXfield raised to the specified power. 1370 """ 1371 try: 1372 return NXfield(value=pow(self.nxdata,power), name=self.nxname, 1373 attrs=self.attrs) 1374 except TypeError, message: 1375 raise NeXusError, message 1376 1377 def reshape(self, shape): 1378 """ 1379 Returns an NXfield with shape. 1380 """ 1381 self.shape = list(shape) 1079 1382 if isinstance(self.nxdata, np.ndarray): self.nxdata.shape = shape 1080 1383 return self 1081 1384 1082 def nxsum(self, axis=None): 1083 """ 1084 Returns a scalar value or Numpy array containing the data summed 1085 along one or more axes. The default is to return a sum over the entire 1086 array. Equivalent to the Numpy ndarray.sum. 1087 """ 1088 return self.nxdata.sum(axis) 1089 1090 def nxtranspose(self,shape=None):#added shape variable here 9/8/2010 1091 """ 1092 Returns an SDS containing the transpose of the data array. Equivalent 1385 def transpose(self,shape=None):#added shape variable here 9/8/2010 1386 """ 1387 Returns an NXfield containing the transpose of the data array. Equivalent 1093 1388 to the Numpy ndarray.transpose. 1094 1389 """ 1095 1390 # error, no shape variable in this scope 1096 return SDS(value=self.nxdata.transpose(shape), name=self.nxname, 1097 attrs=self.nxattrs) 1098 1099 def nxvar(self, axis=None): 1100 return SDS(value=self.nxdata.var(axis), name="variance", 1101 attrs=self.nxattrs) 1102 1103 def nxcenters(self): 1104 """ 1105 Returns an SDS with the centers of a single axis 1391 return NXfield(value=self.nxdata.transpose(shape), name=self.nxname, 1392 attrs=self.attrs) 1393 1394 def centers(self): 1395 """ 1396 Returns an NXfield with the centers of a single axis 1106 1397 assuming it contains bin boundaries. 1107 1398 """ 1108 return SDS((self.nxdata[:-1]+self.nxdata[1:])/2,1109 name=self.nxname,attrs=self.nxattrs)1399 return NXfield((self.nxdata[:-1]+self.nxdata[1:])/2, 1400 name=self.nxname,attrs=self.attrs) 1110 1401 1111 1402 def __enter__(self): … … 1120 1411 # file cursor when in the slab context. 1121 1412 # TODO: if HDF allows multiple cursors, extend napi to support them 1122 self._close_on_exit = not self. _file.isopen1123 self. _file.open() # Force file open even if closed1124 self. _file.openpath(self._path)1413 self._close_on_exit = not self.nxroot._file.isopen 1414 self.nxroot._file.open() # Force file open even if closed 1415 self.nxroot._file.openpath(self.nxpath) 1125 1416 self._incontext = True 1126 1417 return self … … 1132 1423 self._incontext = False 1133 1424 if self._close_on_exit: 1134 self. _file.close()1135 1136 def nxget(self, offset, size, units=""):1425 self.nxroot._file.close() 1426 1427 def get(self, offset, size): 1137 1428 """ 1138 1429 Return a slab from the data array. … … 1141 1432 Offset and shape must each have one entry per dimension. 1142 1433 1143 If units are specified, convert the values to the given units1144 before returning them.1145 1146 1434 This operation should be performed in a "with group.data" 1147 1435 context. … … 1151 1439 Corresponds to NXgetslab(handle,data,offset,shape) 1152 1440 """ 1153 self.__enter__() 1154 value = self._file.getslab(offset,size) 1155 self.__exit__() 1156 return self._converter(value,units) 1157 1158 def nxput(self, data, offset): 1441 if self.nxroot._file: 1442 self.__enter__() 1443 value = self.nxroot._file.getslab(offset,size) 1444 self.__exit__() 1445 return value 1446 else: 1447 raise NeXusError, "No input file specified for NXgetslab" 1448 1449 def put(self, data, offset, refresh=True): 1159 1450 """ 1160 1451 Put a slab into the data array. … … 1166 1457 context. 1167 1458 1168 Raises ValueError if this fails. No error is raised when1459 Raises NeXusError if this fails. No error is raised when 1169 1460 writing to a file which is open read-only. 1170 1461 1171 1462 Corresponds to NXputslab(handle,data,offset,shape) 1172 1463 """ 1173 self.__enter__() 1174 self._file.putslab(data, offset, data.shape) 1175 self.__exit__() 1176 1464 if self.nxroot._file: 1465 if self.nxroot._file.mode == napi.ACC_READ: 1466 raise NeXusError, "NeXus file is readonly" 1467 self.__enter__() 1468 if isinstance(data, NXfield): 1469 self.nxroot._file.putslab(data.nxdata.astype(self.dtype), offset, 1470 data.shape) 1471 else: 1472 data = np.array(data) 1473 self.nxroot._file.putslab(data.astype(self.dtype), offset, 1474 data.shape) 1475 self.__exit__() 1476 if refresh: self.refresh() 1477 else: 1478 raise NeXusError, "No output file specified for NXputslab" 1479 1480 def add(self, data, offset): 1481 """ 1482 Add a slab into the data array. 1483 1484 Calls get to read in existing data before adding the value 1485 and calling put. It assumes that the two sets of data have 1486 compatible data types. 1487 """ 1488 if isinstance(data, NXfield): 1489 value = self.get(offset, data.shape) 1490 self.put(data.nxdata.astype(self.dtype)+value, offset) 1491 else: 1492 value = self.get(offset, data.shape) 1493 self.put(data.astype(self.dtype)+value, offset) 1494 1495 def refresh(self): 1496 """ 1497 Rereads the data from the file. 1498 1499 Calls net to read in data again. If put has been called, then 1500 nxdata is no longer synchronized with the file making a refresh 1501 necessary. This will only be performed if nxdata already stores the 1502 data. 1503 """ 1504 if self._value is not None: 1505 if self.nxroot._file: 1506 self._value = self.nxroot._file.readpath(self.nxpath) 1507 else: 1508 raise NeXusError, "No file specified for reads" 1509 1510 def convert(self, units=""): 1511 """ 1512 Return the data in particular units. 1513 """ 1514 try: 1515 import units 1516 except ImportError: 1517 raise NeXusError, "No conversion utility available" 1518 if self._value is not None: 1519 return self._converter(self._value,units) 1520 else: 1521 return None 1522 1177 1523 def __str__(self): 1178 1524 """ … … 1192 1538 1193 1539 def _str_tree(self,indent=0,attrs=False,recursive=False): 1194 dims = 'x'.join([str(n) for n in self.nxdims]) 1195 #return "%s(%s)"%(self.nxtype, dims) 1540 dims = 'x'.join([str(n) for n in self.shape]) 1196 1541 s = str(self) 1197 1542 if '\n' in s or s == "": 1198 s = "%s(%s)"%(self. nxtype, dims)1543 s = "%s(%s)"%(self.dtype, dims) 1199 1544 v=[" "*indent + "%s = %s"%(self.nxname, s)] 1200 if attrs and self. nxattrs: v.append(self._str_attrs(indent=indent+2))1545 if attrs and self.attrs: v.append(self._str_attrs(indent=indent+2)) 1201 1546 return "\n".join(v) 1202 1547 1203 def nxaxes(self):1204 """ 1205 Return a list of SDSs containing axes.1206 1207 Only works if the SDShas the 'axes' attribute1548 def _getaxes(self): 1549 """ 1550 Return a list of NXfields containing axes. 1551 1552 Only works if the NXfield has the 'axes' attribute 1208 1553 """ 1209 1554 try: 1210 return [getattr(self.nxgroup,name) for name in getAxes(self.axes)]1555 return [getattr(self.nxgroup,name) for name in _readaxes(self.axes)] 1211 1556 except KeyError: 1212 1557 return None 1213 1558 1214 def nxdata_as(self, units=""):1215 """ 1216 Return the data i n particular units.1559 def _getdata(self): 1560 """ 1561 Return the data if it is not larger than NX_MEMORY. 1217 1562 """ 1218 1563 if self._value is None: 1219 if self._file: 1220 self._value = self._file.readpath(self._path) 1564 if self.nxroot._file: 1565 if str(self.dtype) == 'char': 1566 self._value = self.nxroot._file.readpath(self.nxpath) 1567 elif np.prod(self.shape) * np.dtype(self.dtype).itemsize <= NX_MEMORY*1024*1024: 1568 self._value = self.nxroot._file.readpath(self.nxpath) 1569 else: 1570 raise MemoryError, 'Data size larger than NX_MEMORY=%s MB' % NX_MEMORY 1221 1571 else: 1222 1572 return None 1223 if isinstance(self._value, np.ndarray): 1224 self._value = self._value.reshape(self.nxdims) 1225 return self._converter(self._value,units) 1226 1227 def nxdata_set(self, value): 1228 dummy_nxtype, nxdims = _gettype(value) 1229 if nxdims == self.nxdims: 1230 self._value = _settype(value, self.nxtype) 1231 else: 1232 raise NeXusError, "Dimensions do not match SDS" 1233 1234 nxdata = property(nxdata_as,nxdata_set,doc="The data values in default units") 1573 1574 return self._value 1575 1576 def _setdata(self, value): 1577 if value is not None: 1578 if str(self._dtype) == 'char' or isinstance(value,str): 1579 self._value = str(value) 1580 self._shape = (len(self._value),) 1581 self._dtype = 'char' 1582 else: 1583 if self.dtype in np.typeDict: 1584 self._value = np.array(value,self.dtype) 1585 else: 1586 self._value = np.array(value) 1587 self._shape = self._value.shape 1588 self._dtype = self._value.dtype 1589 1590 def _getdtype(self): 1591 return self._dtype 1592 1593 def _getshape(self): 1594 return self._shape 1595 1596 def _getsize(self): 1597 return len(self) 1598 1599 nxdata = property(_getdata,_setdata,doc="The data values") 1600 nxaxes = property(_getaxes,doc="The plotting axes") 1601 dtype = property(_getdtype, "Data type of NeXus field") 1602 shape = property(_getshape, "Shape of NeXus field") 1603 size = property(_getsize, "Size of NeXus field") 1604 1605 SDS = NXfield # For backward compatibility 1606 1607 def _fixaxes(signal, axes): 1608 """ 1609 Remove length-one dimensions from plottable data 1610 """ 1611 shape = list(signal.shape) 1612 while 1 in shape: shape.remove(1) 1613 newaxes = [] 1614 for axis in axes: 1615 if axis.size > 1: newaxes.append(axis) 1616 return signal.nxdata.view().reshape(shape), newaxes 1235 1617 1236 1618 class PylabPlotter(object): 1237 """ 1238 Matplotlib plotter object for NeXus data nodes. 1239 """ 1240 def plot(self, signal, axes, title, errors=None, **opts): 1619 1620 """ 1621 Matplotlib plotter class for NeXus data. 1622 """ 1623 1624 def plot(self, signal, axes, title, errors, **opts): 1241 1625 """ 1242 1626 Plot the data entry. … … 1244 1628 Raises NeXusError if the data cannot be plotted. 1245 1629 """ 1246 import pylab 1630 try: 1631 import pylab 1632 except ImportError: 1633 raise NeXusError, "Plotting package not available." 1247 1634 if "over" in opts.keys(): 1248 1635 over = True … … 1258 1645 logplot = False 1259 1646 1647 # Provide a new view of the data if there is a dimension of length 1 1648 if 1 in signal.shape: 1649 data, axes = _fixaxes(signal, axes) 1650 else: 1651 data = signal.nxdata 1652 1260 1653 # Find the centers of the bins for histogrammed data 1261 axis_data = centers( signal, axes)1654 axis_data = centers(data, axes) 1262 1655 1263 1656 #One-dimensional Plot 1264 if len( signal.nxdims) == 1:1657 if len(data.shape) == 1: 1265 1658 if hasattr(signal, 'units'): 1266 if not errors and signal.units .nxdata== 'counts':1267 errors = SDS(np.sqrt(signal.nxdata))1659 if not errors and signal.units == 'counts': 1660 errors = NXfield(np.sqrt(data)) 1268 1661 if logplot: 1269 data = np.log10(np.clip(signal.nxdata,0,1e8)) 1270 if errors: ebars = np.log10(errors.nxdata) 1271 else: 1272 data = signal.nxdata 1273 if errors: ebars = errors.nxdata 1662 data = np.log10(np.clip(data,0,1e8)) 1663 if errors: ebars = np.log10(errors) 1664 elif errors: 1665 ebars = errors.nxdata 1274 1666 if errors: 1275 1667 myopts=copy(opts) 1276 1668 myopts.setdefault('fmt','o') 1277 1669 myopts.setdefault('linestyle','None') 1278 pylab.scatter(axis_data[0], signal.nxdata, **opts)1279 pylab.errorbar(axis_data[0], signal.nxdata, ebars, **myopts)1670 pylab.scatter(axis_data[0], data, **opts) 1671 pylab.errorbar(axis_data[0], data, ebars, **myopts) 1280 1672 else: 1281 pylab.scatter(axis_data[0], signal.nxdata, **opts)1673 pylab.scatter(axis_data[0], data, **opts) 1282 1674 if not over: 1283 1675 pylab.xlabel(label(axes[0])) … … 1287 1679 #Two dimensional plot 1288 1680 else: 1681 if len(data.shape) > 2: 1682 slab = [slice(None), slice(None)] 1683 for _dim in data.shape[2:]: 1684 slab.append(0) 1685 data = data[slab].view().reshape(data.shape[:2]) 1686 print "Warning: Only the top 2D slice of the data is plotted" 1289 1687 #from api.nexus import meshgl 1290 1688 #gridplot = meshgl.pcolor_gl 1291 1689 #gridplot = pylab.pcolormesh 1292 if len(signal.nxdims) == 2:1293 data = signal.nxdata1294 else:1295 slab = [slice(None), slice(None)]1296 for dummy in signal.nxdims[2:]:1297 slab.append(0)1298 data = signal[slab].nxreshape(signal.nxdims[:2]).nxdata1299 print "Warning: Only the top 2D slice of the data is plotted"1300 1690 gridplot = imshow_irregular 1301 # if hasattr(signal, 'units') and signal.units == 'counts':1302 1691 if logplot: 1303 1692 gridplot(axis_data[0], axis_data[1], … … 1309 1698 pylab.title(title) 1310 1699 1311 #For higher-dimensional plots, choose limits1312 #else:1313 #raise NeXusError, "Only one and two-dimensional plots currently supported"1314 1315 1700 @staticmethod 1316 1701 def show(): … … 1318 1703 pylab.show() 1319 1704 1320 class NXgroup(NXnode): 1321 """ 1322 A NeXus group node. 1323 1324 This is a subclass of NXnode and is the base class for the specific 1705 1706 class NXgroup(NXobject): 1707 1708 """ 1709 A NeXus group object. 1710 1711 This is a subclass of NXobject and is the base class for the specific 1325 1712 NeXus group classes, e.g., NXentry, NXsample, NXdata. 1326 1713 … … 1332 1719 arguments. 1333 1720 1334 Positional Arguments : These must be valid NeXus nodes, either an SDS1721 Positional Arguments : These must be valid NeXus objects, either an NXfield 1335 1722 or a NeXus group. These are added without modification as children of this 1336 1723 group. … … 1338 1725 Keyword Arguments : Apart from a list of special keywords shown below, 1339 1726 keyword arguments are used to add children to the group using the keywords 1340 as attribute names. The values can either be valid SDS dataor NXgroups,1341 in which case the 'n xname' attribute is changed to the keyword, or they1342 can be numerical or string data, which are converted to SDSobjects.1727 as attribute names. The values can either be valid NXfields or NXgroups, 1728 in which case the 'name' attribute is changed to the keyword, or they 1729 can be numerical or string data, which are converted to NXfield objects. 1343 1730 1344 1731 Special Keyword Arguments: … … 1346 1733 name : string 1347 1734 The name of the NXgroup, which is directly accessible as the NXgroup 1348 attribute 'n xname'. If the NXgroup is initialized as the attribute of1349 a parent node, the name is automatically set to the name of this1735 attribute 'name'. If the NXgroup is initialized as the attribute of 1736 a parent group, the name is automatically set to the name of this 1350 1737 attribute. If 'nxclass' is specified and has the usual prefix 'NX', 1351 1738 the default name is the class name without this prefix. … … 1357 1744 arguments. 1358 1745 file : filename 1359 The file from which the SDShas been read.1746 The file from which the NXfield has been read. 1360 1747 path : string 1361 The path to this nodewith respect to the root of the NeXus tree,1748 The path to this object with respect to the root of the NeXus tree, 1362 1749 using the convention for unix file paths. 1363 group : NX node(NXgroup or subclass of NXgroup)1364 The parent NeXus node, which is accessible as the group attribute1365 ' nxgroup'. If the group is initialized as the attribute of1366 a parent node, this is set to the parent node.1367 1368 Attributes1369 ---------- 1750 group : NXobject (NXgroup or subclass of NXgroup) 1751 The parent NeXus group, which is accessible as the group attribute 1752 'group'. If the group is initialized as the attribute of 1753 a parent group, this is set to the parent group. 1754 1755 Python Attributes 1756 ----------------- 1370 1757 nxclass : string 1371 The class of the NX node.1758 The class of the NXobject. 1372 1759 nxname : string 1373 The name of the SDS. 1374 nxentries : dict 1375 A dictionary of all the group entries. 1376 nxattrs : dict 1377 A dictionary of the group attributes. 1760 The name of the NXfield. 1761 entries : dictionary 1762 A dictionary of all the NeXus objects contained within an NXgroup. 1763 attrs : dictionary 1764 A dictionary of all the NeXus attributes, i.e., attribute with class NXattr. 1765 entries : dictionary 1766 A dictionary of all the NeXus objects contained within the group. 1767 attrs : dictionary 1768 A dictionary of all the group's NeXus attributes, which all have the 1769 class NXattr. 1378 1770 nxpath : string 1379 The path to this nodewith respect to the root of the NeXus tree. For1771 The path to this object with respect to the root of the NeXus tree. For 1380 1772 NeXus data read from a file, this will be a group of class NXroot, but 1381 1773 if the NeXus tree was defined interactively, it can be any valid 1382 NXgroup. This is determined by recursively accessing the 'nxgroup' 1383 attributes of the parent nodes. 1774 NXgroup. 1775 nxroot : NXgroup 1776 The root object of the NeXus tree containing this object. For 1777 NeXus data read from a file, this will be a group of class NXroot, but 1778 if the NeXus tree was defined interactively, it can be any valid 1779 NXgroup. 1780 1781 NeXus Group Entries 1782 ------------------- 1783 Just as in a NeXus file, NeXus groups can contain either data or other 1784 groups, represented by NXfield and NXgroup objects respectively. To 1785 distinguish them from regular Python attributes, all NeXus objects are 1786 stored in the 'entries' dictionary of the NXgroup. However, they can usually 1787 be assigned or referenced as if they are Python attributes, i.e., using the 1788 dictionary name directly as the group attribute name, as long as this name 1789 is not the same as one of the Python attributes defined above or as one of 1790 the NXfield Python attributes. 1791 1792 a) Assigning a NeXus object to a NeXus group 1793 1794 In the example below, after assigning the NXgroup, the following three 1795 NeXus object assignments to entry.sample are all equivalent: 1796 1797 >>> entry.sample = NXsample() 1798 >>> entry.sample['temperature'] = NXfield(40.0) 1799 >>> entry.sample.temperature = NXfield(40.0) 1800 >>> entry.sample.temperature = 40.0 1801 >>> entry.sample.temperature 1802 NXfield(40.0) 1803 1804 If the assigned value is not a valid NXobject, then it is cast as an NXfield 1805 with a type determined from the Python data type. 1806 1807 >>> entry.sample.temperature = 40.0 1808 >>> entry.sample.temperature 1809 NXfield(40.0) 1810 >>> entry.data.data.x=np.linspace(0,10,11).astype('float32') 1811 >>> entry.data.data.x 1812 NXfield([ 0. 1. 2. ..., 8. 9. 10.]) 1813 1814 b) Referencing a NeXus object in a NeXus group 1815 1816 If the name of the NeXus object is not the same as any of the Python 1817 attributes listed above, or the methods listed below, they can be referenced 1818 as if they were a Python attribute of the NXgroup. However, it is only possible 1819 to reference attributes with one of the proscribed names using the group 1820 dictionary, i.e., 1821 1822 >>> entry.sample.tree = 100.0 1823 >>> entry.sample.tree 1824 sample:NXsample 1825 tree = 100.0 1826 >>> entry.sample['tree'] 1827 NXfield(100.0) 1828 1829 For this reason, it is recommended to use the group dictionary to reference 1830 all group objects within Python scripts. 1831 1832 NeXus Attributes 1833 ---------------- 1834 NeXus attributes are not currently used much with NXgroups, except for the 1835 root group, which has a number of global attributes to store the file name, 1836 file creation time, and NeXus and HDF version numbers. However, the 1837 mechanism described for NXfields works here as well. All NeXus attributes 1838 are stored in the 'attrs' dictionary of the NXgroup, but can be referenced 1839 as if they are Python attributes as long as there is no name clash. 1840 1841 >>> entry.sample.temperature = 40.0 1842 >>> entry.sample.attrs['tree'] = 10.0 1843 >>> entry.sample.tree 1844 sample:NXsample 1845 @tree = 10.0 1846 temperature = 40.0 1847 >>> entry.sample.attrs['tree'] 1848 NXattr(10.0) 1384 1849 1385 1850 Methods 1386 1851 ------- 1387 nxdir(self, attrs=False): 1852 insert(self, NXobject, name='unknown'): 1853 Insert a valid NXobject (NXfield or NXgroup) into the group. 1854 1855 If NXobject has a 'name' attribute and the 'name' keyword is not given, 1856 then the object is inserted with the NXobject name. 1857 1858 makelink(self, NXobject): 1859 Add the NXobject to the group entries as a link (NXlink). 1860 1861 dir(self, attrs=False, recursive=False): 1388 1862 Print the group directory. 1389 1863 1390 The directory is a list of NeXus objects within this group, either 1391 NeXus groups or SDS data. If 'attrs' is True, SDS attributes are 1392 displayed. If 'recursive' is True, the contents of child groups are 1393 also displayed. 1394 1395 nxtree(self, attrs=True): 1396 Print the SDS and its attributes. 1397 1398 It invokes the 'nxdir' method with both 'attrs' and 'recursive' 1399 set to True. 1400 1401 nxsave(filename, format='w5') 1864 The directory is a list of NeXus objects within this group, either NeXus 1865 groups or NXfield data. If 'attrs' is True, NXfield attributes are 1866 displayed. If 'recursive' is True, the contents of child groups are also 1867 displayed. 1868 1869 tree: 1870 Print the group tree. 1871 1872 It invokes the 'dir' method with both 'attrs' and 'recursive' 1873 set to True. Note that this method is defined as a property attribute and 1874 does not require parentheses. 1875 1876 save(self, filename, format='w5') 1402 1877 Save the NeXus group into a file 1403 1878 … … 1406 1881 a valid NeXus file. 1407 1882 1408 nxsave(filename, format='w5')1409 Save the NeXus group into a file1410 1411 The object is wrapped in an NXroot group (with name 'root') and an1412 NXentry group (with name 'entry'), if necessary, in order to produce1413 a valid NeXus file.1414 1415 1883 Examples 1416 1884 -------- 1417 >>> x = SDS(np.linspace(0,2*np.pi,101), units='degree')1885 >>> x = NXfield(np.linspace(0,2*np.pi,101), units='degree') 1418 1886 >>> entry = NXgroup(x, name='entry', nxclass='NXentry') 1419 >>> entry.sample = NXgroup(temperature= SDS(40.0,units='K'),1887 >>> entry.sample = NXgroup(temperature=NXfield(40.0,units='K'), 1420 1888 nxclass='NXsample') 1421 >>> entry.sample. nxtree()1889 >>> entry.sample.tree 1422 1890 sample:NXsample 1423 1891 temperature = 40.0 … … 1429 1897 1430 1898 >>> entry = NXentry(x) 1431 >>> entry.sample = NXsample(temperature=SDS(40.0,units='K')) 1899 >>> entry.sample = NXsample(temperature=NXfield(40.0,units='K')) 1900 1901 or 1902 1903 >>> entry.sample.temperature = 40.0 1904 >>> entry.sample.temperature.units='K' 1432 1905 1433 1906 """ 1434 # Plotter to use for nxplot calls 1907 1908 # Plotter to use for plot calls 1435 1909 _plotter = PylabPlotter() 1436 1910 1437 1911 def __init__(self, *items, **opts): 1438 1912 if "name" in opts.keys(): 1439 self. nxname = opts["name"]1913 self._name = opts["name"] 1440 1914 del opts["name"] 1915 self._entries = {} 1441 1916 if "entries" in opts.keys(): 1442 1917 for k,v in opts["entries"].items(): 1443 1918 setattr(self, k, v) 1444 1919 del opts["entries"] 1920 self._attrs = AttrDict() 1445 1921 if "attrs" in opts.keys(): 1446 1922 self._setattrs(opts["attrs"]) 1447 1923 del opts["attrs"] 1924 if "nxclass" in opts.keys(): 1925 self._class = opts["nxclass"] 1926 del opts["nxclass"] 1448 1927 for k,v in opts.items(): 1449 1928 setattr(self, k, v) 1450 if self.nxname == "unknown" and self.nxclass.startswith("NX"): 1451 self.nxname = self.nxclass[2:] 1929 if self.nxclass.startswith("NX"): 1930 if self.nxname == "unknown": self._name = self.nxclass[2:] 1931 try: # If one exists, set the class to a valid NXgroup subclass 1932 self.__class__ = globals()[self.nxclass] 1933 except KeyError: 1934 pass 1452 1935 for item in items: 1453 1936 try: 1454 1937 setattr(self, item.nxname, item) 1455 1938 except AttributeError: 1456 raise NeXusError, "Non-keyword arguments must be valid NX nodes"1939 raise NeXusError, "Non-keyword arguments must be valid NXobjects" 1457 1940 1458 1941 # def __cmp__(self, other): … … 1463 1946 # return cmp(self.nxname, other.nxname) 1464 1947 1948 def __repr__(self): 1949 return "%s('%s')" % (self.__class__.__name__,self.nxname) 1950 1465 1951 def _str_value(self,indent=0): 1466 1952 return "" … … 1468 1954 def __getattr__(self, key): 1469 1955 """ 1470 Provide direct access to nodes via nxclass name.1956 Provide direct access to groups via nxclass name. 1471 1957 """ 1472 1958 if key.startswith('NX'): 1473 return self.nxcomponent(key) 1959 return self.component(key) 1960 elif key in self.entries: 1961 return self.entries[key] 1962 elif key in self.attrs: 1963 return self.attrs[key].nxdata 1474 1964 raise KeyError(key+" not in "+self.nxclass+":"+self.nxname) 1475 1965 1476 1966 def __setattr__(self, name, value): 1477 1967 """ 1478 Set a node attribute as a nodeor regular Python attribute.1968 Set an attribute as an object or regular Python attribute. 1479 1969 1480 1970 It is assumed that attributes starting with 'nx' or '_' are regular 1481 Python attributes. All other attributes are converted to valid NX nodes,1482 with class SDS, NXgroup, or a sub-class of NXgroup, depending on the1971 Python attributes. All other attributes are converted to valid NXobjects, 1972 with class NXfield, NXgroup, or a sub-class of NXgroup, depending on the 1483 1973 assigned value. 1484 1974 1485 The internal value of the attribute name, i.e., 'n xname', is set to the1975 The internal value of the attribute name, i.e., 'name', is set to the 1486 1976 attribute name used in the assignment. The parent group of the 1487 attribute, i.e., ' nxgroup', is set to the parent nodeof the attribute.1977 attribute, i.e., 'group', is set to the parent group of the attribute. 1488 1978 1489 1979 If the assigned value is a numerical (scalar or array) or string object, 1490 it is converted to an object of class SDS, whose attribute, 'nxdata',1980 it is converted to an object of class NXfield, whose attribute, 'nxdata', 1491 1981 is set to the assigned value. 1492 1982 """ 1493 if isinstance(value, NXattr) or name.startswith('nx') orname.startswith('_'):1983 if name.startswith('_'): 1494 1984 object.__setattr__(self, name, value) 1495 elif isinstance(value, NXnode): 1496 value.nxgroup = self 1497 value.nxname = name 1498 object.__setattr__(self, name, value) 1499 else: 1500 object.__setattr__(self, name, SDS(value=value, name=name, group=self)) 1985 elif isinstance(value, NXattr): 1986 self._attrs[name] = value 1987 else: 1988 self[name] = value 1501 1989 1502 1990 def __getitem__(self, index): 1503 1991 """ 1504 1992 Returns a slice from the NXgroup nxsignal attribute (if it exists) as 1505 a new NXdata group .1506 1507 In most cases, the slice values are applied to the SDSnxdata array1508 and returned within an SDSobject with the same metadata. However,1993 a new NXdata group, if the index is a slice object. 1994 1995 In most cases, the slice values are applied to the NXfield nxdata array 1996 and returned within an NXfield object with the same metadata. However, 1509 1997 if the array is one-dimensional and the index start and stop values 1510 1998 are real, the nxdata array is returned with values between the limits … … 1514 2002 decreasing) one-dimensional arrays. 1515 2003 """ 2004 if isinstance(index, str): #i.e., requesting a dictionary value 2005 return self._entries[index] 2006 1516 2007 if not self.nxsignal: 1517 2008 raise NeXusError, "No plottable signal" … … 1552 2043 for axis in result.nxaxes: 1553 2044 if len(axis) > 1: axes.append(axis) 1554 result._setaxes(axes) 2045 result.nxsignal.axes = ":".join([axis.nxname for axis in axes]) 2046 if self.nxtitle: 2047 result.title = self.nxtitle 1555 2048 return result 1556 2049 1557 def _setSDS(self, value, name): 1558 if isinstance(value, list) or isinstance(value, tuple): 1559 setattr(self, name, SDS(value=np.array(value), name=name)) 1560 return name 1561 elif isinstance(value, np.ndarray): 1562 setattr(self, name, SDS(value=value, name=name)) 1563 return name 1564 elif isinstance(value, SDS): 1565 if value.nxname == 'unknown': value.nxname = name 1566 setattr(self, value.nxname, value) 1567 return value.nxname 1568 else: 1569 raise NeXusError, "%s: '%s' should be a Numpy array or an SDS" % (type(value), name) 1570 1571 def _setaxes(self, axes): 1572 #print "_setaxes", signal.nxname, id(signal) 1573 self.nxsignal.axes = ":".join([axis.nxname for axis in axes]) 1574 1575 def _fixaxes(self, signal): 1576 """ 1577 Remove length-one dimensions from plottable data 1578 """ 1579 if isinstance(signal, NXlinkdata): signal = signal.nxlink 1580 while 1 in signal.nxdims: signal.nxdims.remove(1) 1581 axes = [] 1582 for axisname in getAxes(signal.axes): 1583 axis = getattr(self,axisname) 1584 if len(axis) > 1: axes.append(axis) 1585 signal.axes = ":".join([axis.nxname for axis in axes]) 1586 1587 def nxinsert(self, node): 1588 """ 1589 Add a valid NeXus node (SDS or NXgroup) to the group 1590 """ 1591 if isinstance(node, NXnode): 1592 node.nxgroup = self 1593 object.__setattr__(self, node.nxname, node) 1594 1595 def nxsum(self, axis=None): 2050 def __setitem__(self, key, value): 2051 """ 2052 Includes a NeXus group item by adding it to the 'entries' dictionary. 2053 """ 2054 if isinstance(value, NXlink): 2055 self._entries[key] = value 2056 elif isinstance(value, NXobject): 2057 if value.nxgroup is not None: 2058 memo = {} 2059 value = deepcopy(value, memo) 2060 value._attrs = copy(value._attrs) 2061 value._group = self 2062 value._name = key 2063 self._entries[key] = value 2064 else: 2065 self._entries[key] = NXfield(value=value, name=key, group=self) 2066 2067 def __deepcopy__(self, memo): 2068 dpcpy = self.__class__() 2069 memo[id(self)] = dpcpy 2070 for k,v in self.items(): 2071 if isinstance(v, NXgroup): 2072 dpcpy[k] = deepcopy(v, memo) 2073 else: 2074 dpcpy[k] = copy(v) 2075 for k, v in self.attrs.items(): 2076 dpcpy.attrs[k] = copy(v) 2077 return dpcpy 2078 2079 def keys(self): 2080 """ 2081 Returns the names of NeXus objects in the group. 2082 """ 2083 return self._entries.keys() 2084 2085 def values(self): 2086 """ 2087 Returns the values of NeXus objects in the group. 2088 """ 2089 return self._entries.values() 2090 2091 def items(self): 2092 """ 2093 Returns a list of the NeXus objects in the group as (key,value) pairs. 2094 """ 2095 return self._entries.items() 2096 2097 def has_key(self, name): 2098 """ 2099 Returns true if the NeXus object with the specified name is in the group. 2100 """ 2101 return self._entries.has_key(name) 2102 2103 def insert(self, value, name='unknown'): 2104 """ 2105 Adds an attribute to the group. 2106 2107 If it is not a valid NeXus object (NXfield or NXgroup), the attribute 2108 is converted to an NXfield. 2109 """ 2110 if isinstance(value, NXobject): 2111 if name == 'unknown': name = value.nxname 2112 if name in self._entries: 2113 raise NeXusError, "'%s' already exists in group" % name 2114 value._group = self 2115 self._entries[name] = value 2116 else: 2117 self._entries[name] = NXfield(value=value, name=name, group=self) 2118 2119 def makelink(self, target): 2120 """ 2121 Creates a linked NXobject within the group. 2122 2123 All attributes are inherited from the parent object including the name 2124 """ 2125 if isinstance(target, NXobject): 2126 self.entries[target.nxname] = NXlink(target=target, name=target.nxname, group=self) 2127 else: 2128 raise NeXusError, "Link target must be an NXobject" 2129 2130 2131 def sum(self, axis=None): 1596 2132 """ 1597 2133 Return the sum of the NXdata group using the Numpy sum method … … 1606 2142 raise NeXusError, "Summing not allowed for groups of unknown class" 1607 2143 if axis is None: 1608 return self.nxsignal. nxsum()1609 else: 1610 signal = SDS(self.nxsignal.nxsum(axis), name=self.nxsignal.nxname)2144 return self.nxsignal.sum() 2145 else: 2146 signal = NXfield(self.nxsignal.sum(axis), name=self.nxsignal.nxname) 1611 2147 axes = self.nxaxes 1612 2148 summedaxis = axes.pop(axis) … … 1615 2151 signal.long_name = "Integral from %s to %s %s" % \ 1616 2152 (summedaxis[0], summedaxis[-1], units) 1617 average = SDS(0.5*(summedaxis.nxdata[0]+summedaxis.nxdata[-1]), name=summedaxis.nxname)2153 average = NXfield(0.5*(summedaxis.nxdata[0]+summedaxis.nxdata[-1]), name=summedaxis.nxname) 1618 2154 if units: average.units = units 1619 2155 result = NXdata(signal, axes, average) 1620 2156 if self.nxerrors: 1621 2157 errors = np.sqrt((self.nxerrors.nxdata**2).sum(axis)) 1622 result.errors = SDS(errors, name="errors") 2158 result.errors = NXfield(errors, name="errors") 2159 if self.nxtitle: 2160 result.title = self.nxtitle 1623 2161 return result 1624 2162 1625 def nxmoment(self, order=1):1626 """ 1627 Return an SDScontaining the moments of the NXdata group2163 def moment(self, order=1): 2164 """ 2165 Return an NXfield containing the moments of the NXdata group 1628 2166 assuming the signal is one-dimensional. 1629 2167 … … 1633 2171 if not self.nxsignal: 1634 2172 raise NeXusError, "No signal to calculate" 1635 elif len(self.nxsignal. nxdims) > 1:2173 elif len(self.nxsignal.shape) > 1: 1636 2174 raise NeXusError, "Operation only possible on one-dimensional signals" 1637 2175 elif order > 1: … … 1639 2177 if not hasattr(self,"nxclass"): 1640 2178 raise NeXusError, "Operation not allowed for groups of unknown class" 1641 return (centers(self.nxsignal,self.nxaxes)*self.nxsignal). nxsum() \1642 /self.nxsignal. nxsum()1643 1644 def nxcomponent(self, nxclass):1645 """ 1646 Find all child nodes that have a particular class.1647 """ 1648 return [E for dummy_name,E in self.nxentries.items() if E.nxclass==nxclass]1649 1650 def nxsignals(self):1651 """ 1652 Return a dictionary of SDS's containing signal data.2179 return (centers(self.nxsignal,self.nxaxes)*self.nxsignal).sum() \ 2180 /self.nxsignal.sum() 2181 2182 def component(self, nxclass): 2183 """ 2184 Find all child objects that have a particular class. 2185 """ 2186 return [E for _name,E in self.entries.items() if E.nxclass==nxclass] 2187 2188 def signals(self): 2189 """ 2190 Return a dictionary of NXfield's containing signal data. 1653 2191 1654 2192 The key is the value of the signal attribute. 1655 2193 """ 1656 2194 signals = {} 1657 for node in self.nxentries.values():1658 if 'signal' in node.nxattrs:1659 signals[ node.signal.nxdata] = node2195 for obj in self.entries.values(): 2196 if 'signal' in obj.attrs: 2197 signals[obj.nxsignal.nxdata] = obj 1660 2198 return signals 1661 2199 1662 2200 def _signal(self): 1663 2201 """ 1664 Return the SDS containing the signal data. 1665 """ 1666 for node in self.nxentries.values(): 1667 if 'signal' in node.nxattrs and str(node.signal.nxdata) == '1': 1668 if 1 in node.nxdims: self._fixaxes(node) 1669 return self.__dict__[node.nxname] 2202 Return the NXfield containing the signal data. 2203 """ 2204 for obj in self.entries.values(): 2205 if 'signal' in obj.attrs and str(obj.signal) == '1': 2206 # if isinstance(self[obj.nxname],NXlink): 2207 # return self[obj.nxname].nxlink 2208 # else: 2209 return self[obj.nxname] 1670 2210 return None 1671 2211 1672 2212 def _axes(self): 1673 2213 """ 1674 Return a list of SDSs containing the axes.2214 Return a list of NXfields containing the axes. 1675 2215 """ 1676 2216 try: 1677 return [getattr(self,name) for name in getAxes(self.nxsignal.axes)]2217 return [getattr(self,name) for name in _readaxes(self.nxsignal.axes)] 1678 2218 except KeyError: 1679 2219 axes = {} 1680 for node in self.nxentries:1681 if 'axis' in getattr(self, node).nxattrs:1682 axes[getattr(self, node).axis.nxdata] = getattr(self,node)2220 for obj in self.entries: 2221 if 'axis' in getattr(self,obj).attrs: 2222 axes[getattr(self,obj).axis] = getattr(self,obj) 1683 2223 return [axes[key] for key in sorted(axes.keys())] 1684 2224 1685 2225 def _errors(self): 1686 2226 """ 1687 Return the SDScontaining the signal errors.2227 Return the NXfield containing the signal errors. 1688 2228 """ 1689 2229 try: 1690 return self. nxentries['errors']2230 return self.entries['errors'] 1691 2231 except KeyError: 1692 2232 return None 1693 2233 1694 nxsignal = property(_signal, "Signal SDS within group") 2234 def _title(self): 2235 """ 2236 Return the title as a string. 2237 2238 If there is no title attribute in the string, the parent 2239 NXentry group in the group's path is searched. 2240 """ 2241 title = self.nxpath 2242 if 'title' in self.entries: 2243 return str(self.title) 2244 else: 2245 obj = self 2246 while obj.nxgroup is not None: 2247 try: 2248 if obj.nxclass == 'NXentry': return str(obj.title) 2249 except KeyError: 2250 pass 2251 obj = obj.nxgroup 2252 return self.nxpath 2253 2254 def _getentries(self): 2255 return self._entries 2256 2257 nxsignal = property(_signal, "Signal NXfield within group") 1695 2258 nxaxes = property(_axes, "List of axes within group") 1696 nxerrors = property(_errors, "Errors SDS within group") 1697 1698 def nxplot(self, signal=None, **opts): 2259 nxerrors = property(_errors, "Errors NXfield within group") 2260 nxtitle = property(_title, "Title for group plot") 2261 entries = property(_getentries,doc="NeXus objects within group") 2262 2263 2264 def plot(self, **opts): 1699 2265 """ 1700 2266 Plot data contained within the group. … … 1707 2273 group = group.NXentry[0] 1708 2274 if group.nxclass == "NXentry": 1709 group = group.NXdata[0] 2275 try: 2276 group = group.NXdata[0] 2277 except IndexError: 2278 raise NeXusError('No NXdata group found') 1710 2279 1711 2280 # Find a plottable signal 1712 if signal is None: 1713 signal = group.nxsignal 1714 if not signal: 1715 raise NeXusError('No plottable signal defined') 2281 signal = group.nxsignal 2282 if not signal: 2283 raise NeXusError('No plottable signal defined') 1716 2284 1717 2285 # Find errors … … 1720 2288 # Find the associated axes 1721 2289 axes = group.nxaxes 1722 2290 1723 2291 # Construct title 1724 path = [] 1725 node = group 1726 title = '' 1727 while node.nxgroup is not None: 1728 try: 1729 if node.nxclass == 'NXentry': title = node.title.nxdata 1730 except KeyError: 1731 pass 1732 path = [node.nxname] + path 1733 node = node.nxgroup 2292 title = group.nxtitle 1734 2293 1735 2294 # Plot with the available plotter … … 1737 2296 1738 2297 1739 class NXroot(NXgroup): 1740 """ 1741 NXroot node. This is a subclass of the NXgroup class. 1742 1743 See the NXgroup documentation for more details. 1744 """ 1745 def __init__(self, *items, **opts): 1746 self.nxclass = "NXroot" 1747 NXgroup.__init__(self, *items, **opts) 1748 2298 class NXlink(NXobject): 2299 2300 """ 2301 Class for NeXus linked objects. 2302 2303 The real object will be accessible by following the link attribute. 2304 """ 2305 2306 _class = "NXlink" 2307 2308 def __init__(self, target=None, name='link', group=None): 2309 self._group = group 2310 self._name = name 2311 if isinstance(target, NXobject): 2312 self._target = target.nxpath 2313 if target.nxclass == "NXlink": 2314 raise NeXusError, "Cannot link to another NXlink object" 2315 elif target.nxclass == "NXfield": 2316 self.__class__ = NXlinkfield 2317 else: 2318 self.__class__ = NXlinkgroup 2319 else: 2320 self._target = target 2321 2322 def __getattr__(self, key): 2323 try: 2324 try: 2325 return self.nxlink.__dict__[key] 2326 except KeyError: 2327 return self.nxlink.__getattr__(key) 2328 except KeyError: 2329 raise KeyError, (key+" not in %s" % self._target) 2330 2331 def __repr__(self): 2332 return "NXlink('%s')"%(self._target) 2333 2334 def __str__(self): 2335 return "NXlink('%s')"%(self._target) 2336 2337 def _str_tree(self, indent=0, attrs=False, recursive=False): 2338 if self.nxlink: 2339 return self.nxlink._str_tree(indent, attrs, recursive) 2340 else: 2341 return " "*indent+self.nxname+' -> '+self._target 2342 2343 def _getlink(self): 2344 link = self.nxroot 2345 if link: 2346 try: 2347 for level in self._target[1:].split('/'): 2348 link = link.entries[level] 2349 return link 2350 except AttributeError: 2351 return None 2352 else: 2353 return None 2354 2355 def _getattrs(self): 2356 return self.nxlink.attrs 2357 2358 def _getentries(self): 2359 return self.nxlink.entries 2360 2361 nxlink = property(_getlink, "Linked object") 2362 attrs = property(_getattrs,doc="NeXus attributes for object") 2363 entries = property(_getentries,doc="NeXus objects within group") 2364 2365 2366 class NXlinkfield(NXlink, NXfield): 2367 2368 """ 2369 Class for a NeXus linked field. 2370 2371 The real field will be accessible by following the link attribute. 2372 """ 2373 2374 def __setattr__(self, name, value): 2375 if name.startswith('_'): 2376 object.__setattr__(self, name, value) 2377 elif name == "name" or name == "nxclass" or name == "group": 2378 NXfield.__setattr__(self, name, value) 2379 elif self.nxlink: 2380 self.nxlink.__setattr__(name, value) 2381 2382 def get(self, offset, size): 2383 """ 2384 Get a slab from the data array. 2385 2386 Offsets are 0-origin. Shape can be inferred from the data. 2387 Offset and shape must each have one entry per dimension. 2388 2389 This operation should be performed in a "with group.data" 2390 conext. 2391 2392 Raises ValueError cannot convert units. 2393 2394 Corresponds to NXgetslab(handle,data,offset,shape) 2395 """ 2396 if self.nxroot._file: 2397 self.nxlink.__enter__() 2398 value = self.nxlink.nxroot._file.getslab(offset,size) 2399 self.nxlink.__exit__() 2400 else: 2401 raise NeXusError, "No input file specified for NXgetslab" 2402 2403 NXlinkdata = NXlinkfield # For backward compatibility 2404 2405 class NXlinkgroup(NXlink, NXgroup): 2406 2407 """ 2408 Class for a NeXus linked group. 2409 2410 The real group will be accessible by following the link attribute. 2411 """ 2412 2413 def __setattr__(self, name, value): 2414 if name.startswith('_'): 2415 object.__setattr__(self, name, value) 2416 elif name == "name" or name == "nxclass" or name == "group": 2417 NXgroup.__setattr__(self, name, value) 2418 elif self.nxlink: 2419 if not isinstance(value, NXobject): value = NXfield(value=value, name=name) 2420 value._group = self 2421 value._name = name 2422 object.__setattr__(self, name, value) 2423 setattr(self.nxlink, name, value) 2424 2425 1749 2426 class NXentry(NXgroup): 1750 """ 1751 NXentry node. This is a subclass of the NXgroup class. 2427 2428 """ 2429 NXentry group. This is a subclass of the NXgroup class. 1752 2430 1753 2431 Each NXdata and NXmonitor object of the same name will be added … … 1760 2438 See the NXgroup documentation for more details. 1761 2439 """ 2440 1762 2441 def __init__(self, *items, **opts): 1763 self. nxclass = "NXentry"2442 self._class = "NXentry" 1764 2443 NXgroup.__init__(self, *items, **opts) 1765 2444 … … 1768 2447 Add two NXentry objects 1769 2448 """ 1770 result = NXentry(entries=self. nxentries, attrs=self.nxattrs)2449 result = NXentry(entries=self.entries, attrs=self.attrs) 1771 2450 try: 1772 names = [group.nxname for group in self. nxcomponent("NXdata")]2451 names = [group.nxname for group in self.component("NXdata")] 1773 2452 for name in names: 1774 if isinstance(other. __dict__[name], NXdata):1775 result. __dict__[name] = self.__dict__[name] + other.__dict__[name]2453 if isinstance(other.entries[name], NXdata): 2454 result.entries[name] = self.entries[name] + other.entries[name] 1776 2455 else: 1777 2456 raise KeyError 1778 names = [group.nxname for group in self. nxcomponent("NXmonitor")]2457 names = [group.nxname for group in self.component("NXmonitor")] 1779 2458 for name in names: 1780 if isinstance(other. __dict__[name], NXmonitor):1781 result. __dict__[name] = self.__dict__[name] + other.__dict__[name]2459 if isinstance(other.entries[name], NXmonitor): 2460 result.entries[name] = self.entries[name] + other.entries[name] 1782 2461 else: 1783 2462 raise KeyError … … 1790 2469 Subtract two NXentry objects 1791 2470 """ 1792 result = NXentry(entries=self. nxentries, attrs=self.nxattrs)2471 result = NXentry(entries=self.entries, attrs=self.attrs) 1793 2472 try: 1794 names = [group.nxname for group in self. nxcomponent("NXdata")]2473 names = [group.nxname for group in self.component("NXdata")] 1795 2474 for name in names: 1796 if isinstance(other. __dict__[name], NXdata):1797 result. __dict__[name] = self.__dict__[name] - other.__dict__[name]2475 if isinstance(other.entries[name], NXdata): 2476 result.entries[name] = self.entries[name] - other.entries[name] 1798 2477 else: 1799 2478 raise KeyError 1800 names = [group.nxname for group in self. nxcomponent("NXmonitor")]2479 names = [group.nxname for group in self.component("NXmonitor")] 1801 2480 for name in names: 1802 if isinstance(other. __dict__[name], NXmonitor):1803 result. __dict__[name] = self.__dict__[name] - other.__dict__[name]2481 if isinstance(other.entries[name], NXmonitor): 2482 result.entries[name] = self.entries[name] - other.entries[name] 1804 2483 else: 1805 2484 raise KeyError … … 1809 2488 1810 2489 2490 class NXsubentry(NXentry): 2491 2492 """ 2493 NXsubentry group. This is a subclass of the NXsubentry class. 2494 2495 See the NXgroup documentation for more details. 2496 """ 2497 2498 def __init__(self, *items, **opts): 2499 self._class = "NXsubentry" 2500 NXgroup.__init__(self, *items, **opts) 2501 2502 1811 2503 class NXdata(NXgroup): 1812 """ 1813 NXdata node. This is a subclass of the NXgroup class. 2504 2505 """ 2506 NXdata group. This is a subclass of the NXgroup class. 1814 2507 1815 2508 The constructor assumes that the first argument contains the signal and 1816 2509 the second contains either the axis, for one-dimensional data, or a list 1817 of axes, for multidimen ional data. These arguments can either be SDS1818 objects or Numpy arrays, which are converted to SDSobjects with default2510 of axes, for multidimensional data. These arguments can either be NXfield 2511 objects or Numpy arrays, which are converted to NXfield objects with default 1819 2512 names. 1820 2513 … … 1827 2520 Attributes 1828 2521 ---------- 1829 nxsignal : The SDScontaining the attribute 'signal' with value 11830 nxaxes : A list of SDSs containing the signal axes1831 nxerrors : The SDScontaining the errors2522 nxsignal : The NXfield containing the attribute 'signal' with value 1 2523 nxaxes : A list of NXfields containing the signal axes 2524 nxerrors : The NXfield containing the errors 1832 2525 1833 2526 Methods 1834 2527 ------- 1835 nxplot(self, over=False, log=False, **opts)2528 plot(self, over=False, log=False, **opts) 1836 2529 Plot the NXdata group using the defined signal and axes. Valid 1837 2530 Matplotlib parameters, specifying markers, colors, etc, can be 1838 2531 specified using the 'opts' dictionary. 1839 2532 1840 nxmoment(self, order=1)2533 moment(self, order=1) 1841 2534 Calculate moments of the NXdata group. This assumes that the 1842 2535 signal is one-dimenional. Currently, only the first moment is … … 1853 2546 x = float64(101) 1854 2547 >>> X, Y = np.meshgrid(x, x) 1855 >>> z = SDS(sin(X) * sin(Y), name='intensity')2548 >>> z = NXfield(sin(X) * sin(Y), name='intensity') 1856 2549 >>> entry = NXentry() 1857 2550 >>> entry.grid = NXdata(z, (x, x)) 1858 >>> grid. nxtree()2551 >>> grid.tree() 1859 2552 entry:NXentry 1860 2553 grid:NXdata … … 1867 2560 See the NXgroup documentation for more details. 1868 2561 """ 1869 def __init__(self, signal=None, axes=(), *items, **opts): 1870 self.nxclass = "NXdata" 2562 2563 def __init__(self, signal=None, axes=None, *items, **opts): 2564 self._class = "NXdata" 1871 2565 NXgroup.__init__(self, *items, **opts) 1872 2566 if signal is not None: 1873 signalname = self._setSDS(signal, "signal") 1874 self.__dict__[signalname].signal = 1 2567 if isinstance(signal,NXfield): 2568 if signal.nxname == "unknown": signal.nxname = "signal" 2569 if "signal" not in signal.attrs: signal.signal = 1 2570 self[signal.nxname] = signal 2571 signalname = signal.nxname 2572 else: 2573 self["signal"] = signal 2574 self["signal"].signal = 1 2575 signalname = "signal" 1875 2576 if axes is not None: 1876 if isinstance(axes,tuple) or isinstance(axes,list): 1877 axisname = {} 1878 i = 0 1879 for axis in axes: 1880 i = i + 1 1881 axisname[i] = self._setSDS(axis, "axis%s" % i) 1882 self.__dict__[signalname].axes = ":".join(axisname.values()) 1883 else: 1884 axisname = self._setSDS(axes, 'x') 1885 self.__dict__[signalname].axes = axisname 2577 if not isinstance(axes,tuple) and not isinstance(axes,list): 2578 axes = [axes] 2579 axisnames = {} 2580 i = 0 2581 for axis in axes: 2582 i = i + 1 2583 if isinstance(axis,NXfield): 2584 if axis._name == "unknown": axis._name = "axis%s" % i 2585 self[axis.nxname] = axis 2586 axisnames[i] = axis.nxname 2587 else: 2588 axisname = "axis%s" % i 2589 self[axisname] = axis 2590 axisnames[i] = axisname 2591 self[signalname].axes = ":".join(axisnames.values()) 1886 2592 1887 2593 def __add__(self, other): … … 1892 2598 The result contains a copy of all the metadata contained in 1893 2599 the first NXdata group. The module checks that the dimensions are 1894 compatible, but does not check that the SDSnames or values are2600 compatible, but does not check that the NXfield names or values are 1895 2601 identical. This is so that spelling variations or rounding errors 1896 2602 do not make the operation fail. However, it is up to the user to 1897 2603 ensure that the results make sense. 1898 2604 """ 1899 result = NXdata(entries=self. nxentries, attrs=self.nxattrs)2605 result = NXdata(entries=self.entries, attrs=self.attrs) 1900 2606 if isinstance(other, NXdata): 1901 if self.nxsignal and self.nxsignal. nxdims == other.nxsignal.nxdims:1902 result. __dict__[self.nxsignal.nxname] = self.nxsignal + other.nxsignal2607 if self.nxsignal and self.nxsignal.shape == other.nxsignal.shape: 2608 result.entries[self.nxsignal.nxname] = self.nxsignal + other.nxsignal 1903 2609 if self.nxerrors: 1904 2610 if other.nxerrors: … … 1910 2616 raise NeXusError, "Cannot add two arbitrary groups" 1911 2617 else: 1912 result. __dict__[self.nxsignal.nxname] = self.nxsignal + other1913 result. __dict__[self.nxsignal.nxname].nxname = self.nxsignal.nxname2618 result.entries[self.nxsignal.nxname] = self.nxsignal + other 2619 result.entries[self.nxsignal.nxname].nxname = self.nxsignal.nxname 1914 2620 return result 1915 2621 … … 1921 2627 The result contains a copy of all the metadata contained in 1922 2628 the first NXdata group. The module checks that the dimensions are 1923 compatible, but does not check that the SDSnames or values are2629 compatible, but does not check that the NXfield names or values are 1924 2630 identical. This is so that spelling variations or rounding errors 1925 2631 do not make the operation fail. However, it is up to the user to 1926 2632 ensure that the results make sense. 1927 2633 """ 1928 result = NXdata(entries=self. nxentries, attrs=self.nxattrs)2634 result = NXdata(entries=self.entries, attrs=self.attrs) 1929 2635 if isinstance(other, NXdata): 1930 if self.nxsignal and self.nxsignal. nxdims == other.nxsignal.nxdims:1931 result. __dict__[self.nxsignal.nxname] = self.nxsignal - other.nxsignal2636 if self.nxsignal and self.nxsignal.shape == other.nxsignal.shape: 2637 result.entries[self.nxsignal.nxname] = self.nxsignal - other.nxsignal 1932 2638 if self.nxerrors: 1933 2639 if other.nxerrors: … … 1939 2645 raise NeXusError, "Cannot subtract two arbitrary groups" 1940 2646 else: 1941 result. __dict__[self.nxsignal.nxname] = self.nxsignal - other1942 result. __dict__[self.nxsignal.nxname].nxname = self.nxsignal.nxname2647 result.entries[self.nxsignal.nxname] = self.nxsignal - other 2648 result.entries[self.nxsignal.nxname].nxname = self.nxsignal.nxname 1943 2649 return result 1944 2650 … … 1950 2656 The result contains a copy of all the metadata contained in 1951 2657 the first NXdata group. The module checks that the dimensions are 1952 compatible, but does not check that the SDSnames or values are2658 compatible, but does not check that the NXfield names or values are 1953 2659 identical. This is so that spelling variations or rounding errors 1954 2660 do not make the operation fail. However, it is up to the user to 1955 2661 ensure that the results make sense. 1956 2662 """ 1957 result = NXdata(entries=self. nxentries, attrs=self.nxattrs)2663 result = NXdata(entries=self.entries, attrs=self.attrs) 1958 2664 if isinstance(other, NXdata): 1959 2665 1960 2666 # error here signal not defined in this scope 1961 #if self.nxsignal and signal. nxdims == other.nxsignal.nxdims:1962 if self.nxsignal and self.nxsignal. nxdims == other.nxsignal.nxdims:1963 result. __dict__[self.nxsignal.nxname] = self.nxsignal * other.nxsignal2667 #if self.nxsignal and signal.shape == other.nxsignal.shape: 2668 if self.nxsignal and self.nxsignal.shape == other.nxsignal.shape: 2669 result.entries[self.nxsignal.nxname] = self.nxsignal * other.nxsignal 1964 2670 if self.nxerrors: 1965 2671 if other.nxerrors: … … 1972 2678 raise NeXusError, "Cannot multiply two arbitrary groups" 1973 2679 else: 1974 result. __dict__[self.nxsignal.nxname] = self.nxsignal * other1975 result. __dict__[self.nxsignal.nxname].nxname = self.nxsignal.nxname2680 result.entries[self.nxsignal.nxname] = self.nxsignal * other 2681 result.entries[self.nxsignal.nxname].nxname = self.nxsignal.nxname 1976 2682 if self.nxerrors: 1977 2683 result.errors = self.errors * other … … 1993 2699 The result contains a copy of all the metadata contained in 1994 2700 the first NXdata group. The module checks that the dimensions are 1995 compatible, but does not check that the SDSnames or values are2701 compatible, but does not check that the NXfield names or values are 1996 2702 identical. This is so that spelling variations or rounding errors 1997 2703 do not make the operation fail. However, it is up to the user to 1998 2704 ensure that the results make sense. 1999 2705 """ 2000 result = NXdata(entries=self. nxentries, attrs=self.nxattrs)2706 result = NXdata(entries=self.entries, attrs=self.attrs) 2001 2707 if isinstance(other, NXdata): 2002 if self.nxsignal and self.nxsignal. nxdims == other.nxsignal.nxdims:2708 if self.nxsignal and self.nxsignal.shape == other.nxsignal.shape: 2003 2709 # error here, signal and othersignal not defined here 2004 #result. __dict__[self.nxsignal.nxname] = signal / othersignal2005 result. __dict__[self.nxsignal.nxname] = self.nxsignal / other.nxsignal2006 resultvalues = result. __dict__[self.nxsignal.nxname].nxdata2710 #result.entries[self.nxsignal.nxname] = signal / othersignal 2711 result.entries[self.nxsignal.nxname] = self.nxsignal / other.nxsignal 2712 resultvalues = result.entries[self.nxsignal.nxname].nxdata 2007 2713 if self.nxerrors: 2008 2714 if other.nxerrors: … … 2016 2722 raise NeXusError, "Cannot divide two arbitrary groups" 2017 2723 else: 2018 result. __dict__[self.nxsignal.nxname] = self.nxsignal / other2019 result. __dict__[self.nxsignal.nxname].nxname = self.nxsignal.nxname2724 result.entries[self.nxsignal.nxname] = self.nxsignal / other 2725 result.entries[self.nxsignal.nxname].nxname = self.nxsignal.nxname 2020 2726 if self.nxerrors: result.errors = self.errors / other 2021 2727 return result … … 2023 2729 2024 2730 class NXmonitor(NXdata): 2025 """ 2026 NXmonitor node. This is a subclass of the NXdata class. 2731 2732 """ 2733 NXmonitor group. This is a subclass of the NXdata class. 2027 2734 2028 2735 See the NXdata and NXgroup documentation for more details. 2029 2736 """ 2737 2030 2738 def __init__(self, signal=None, axes=(), *items, **opts): 2031 2739 NXdata.__init__(self, signal=signal, axes=axes, *items, **opts) 2032 self.nxclass = "NXmonitor" 2033 if "nxname" not in opts.keys(): 2034 self.nxname = "monitor" 2035 2036 2037 class NXsample(NXgroup): 2038 """ 2039 NXsample node. This is a subclass of the NXgroup class. 2040 2041 See the NXgroup documentation for more details. 2042 """ 2043 def __init__(self, *items, **opts): 2044 self.nxclass = "NXsample" 2045 NXgroup.__init__(self, *items, **opts) 2046 2047 2048 class NXinstrument(NXgroup): 2049 """ 2050 NXinstrument node. This is a subclass of the NXgroup class. 2051 2052 See the NXgroup documentation for more details. 2053 """ 2054 def __init__(self, *items, **opts): 2055 self.nxclass = "NXinstrument" 2056 NXgroup.__init__(self, *items, **opts) 2057 2058 2059 class NXaperture(NXgroup): 2060 """ 2061 NXaperture node. This is a subclass of the NXgroup class. 2062 2063 See the NXgroup documentation for more details. 2064 """ 2065 def __init__(self, *items, **opts): 2066 self.nxclass = "NXaperture" 2067 NXgroup.__init__(self, *items, **opts) 2068 2069 2070 2071 class NXattenuator(NXgroup): 2072 """ 2073 NXattenuator node. This is a subclass of the NXgroup class. 2074 2075 See the NXgroup documentation for more details. 2076 """ 2077 def __init__(self, *items, **opts): 2078 self.nxclass = "NXattenuator" 2079 NXgroup.__init__(self, *items, **opts) 2080 2081 2082 2083 class NXbeam_stop(NXgroup): 2084 """ 2085 NXbeam_stop node. This is a subclass of the NXgroup class. 2086 2087 See the NXgroup documentation for more details. 2088 """ 2089 def __init__(self, *items, **opts): 2090 self.nxclass = "NXbeam_stop" 2091 NXgroup.__init__(self, *items, **opts) 2092 2093 2094 2095 class NXbending_magnet(NXgroup): 2096 """ 2097 NXbending_magnet node. This is a subclass of the NXgroup class. 2098 2099 See the NXgroup documentation for more details. 2100 """ 2101 def __init__(self, *items, **opts): 2102 self.nxclass = "NXbending_magnet" 2103 NXgroup.__init__(self, *items, **opts) 2104 2105 2106 2107 class NXcollimator(NXgroup): 2108 """ 2109 NXcollimator node. This is a subclass of the NXgroup class. 2110 2111 See the NXgroup documentation for more details. 2112 """ 2113 def __init__(self, *items, **opts): 2114 self.nxclass = "NXcollimator" 2115 NXgroup.__init__(self, *items, **opts) 2116 2117 2118 2119 class NXcrystal(NXgroup): 2120 """ 2121 NXcrystal node. This is a subclass of the NXgroup class. 2122 2123 See the NXgroup documentation for more details. 2124 """ 2125 def __init__(self, *items, **opts): 2126 self.nxclass = "NXcrystal" 2127 NXgroup.__init__(self, *items, **opts) 2128 2129 2130 class NXdetector(NXgroup): 2131 """ 2132 NXdetector node. This is a subclass of the NXgroup class. 2133 2134 See the NXgroup documentation for more details. 2135 """ 2136 def __init__(self, *items, **opts): 2137 self.nxclass = "NXdetector" 2138 NXgroup.__init__(self, *items, **opts) 2139 2140 2141 class NXdisk_chopper(NXgroup): 2142 """ 2143 NXdisk_chopper node. This is a subclass of the NXgroup class. 2144 2145 See the NXgroup documentation for more details. 2146 """ 2147 def __init__(self, *items, **opts): 2148 self.nxclass = "NXdisk_chopper" 2149 NXgroup.__init__(self, *items, **opts) 2150 2151 2152 class NXfermi_chopper(NXgroup): 2153 """ 2154 NXfermi_chopper node. This is a subclass of the NXgroup class. 2155 2156 See the NXgroup documentation for more details. 2157 """ 2158 def __init__(self, *items, **opts): 2159 self.nxclass = "NXfermi_chopper" 2160 NXgroup.__init__(self, *items, **opts) 2161 2162 2163 class NXfilter(NXgroup): 2164 """ 2165 NXfilter node. This is a subclass of the NXgroup class. 2166 2167 See the NXgroup documentation for more details. 2168 """ 2169 def __init__(self, *items, **opts): 2170 self.nxclass = "NXfilter" 2171 NXgroup.__init__(self, *items, **opts) 2172 2173 2174 class NXflipper(NXgroup): 2175 """ 2176 NXflipper node. This is a subclass of the NXgroup class. 2177 2178 See the NXgroup documentation for more details. 2179 """ 2180 def __init__(self, *items, **opts): 2181 self.nxclass = "NXflipper" 2182 NXgroup.__init__(self, *items, **opts) 2183 2184 2185 class NXguide(NXgroup): 2186 """ 2187 NXguide node. This is a subclass of the NXgroup class. 2188 2189 See the NXgroup documentation for more details. 2190 """ 2191 def __init__(self, *items, **opts): 2192 self.nxclass = "NXguide" 2193 NXgroup.__init__(self, *items, **opts) 2194 2195 2196 class NXinsertion_device(NXgroup): 2197 """ 2198 NXinsertion_device node. This is a subclass of the NXgroup class. 2199 2200 See the NXgroup documentation for more details. 2201 """ 2202 def __init__(self, *items, **opts): 2203 self.nxclass = "NXinsertion_device" 2204 NXgroup.__init__(self, *items, **opts) 2205 2206 2207 class NXmirror(NXgroup): 2208 """ 2209 NXmirror node. This is a subclass of the NXgroup class. 2210 2211 See the NXgroup documentation for more details. 2212 """ 2213 def __init__(self, *items, **opts): 2214 self.nxclass = "NXmirror" 2215 NXgroup.__init__(self, *items, **opts) 2216 2217 2218 class NXmoderator(NXgroup): 2219 """ 2220 NXmoderator node. This is a subclass of the NXgroup class. 2221 2222 See the NXgroup documentation for more details. 2223 """ 2224 def __init__(self, *items, **opts): 2225 self.nxclass = "NXmoderator" 2226 NXgroup.__init__(self, *items, **opts) 2227 2228 2229 class NXmonochromator(NXgroup): 2230 """ 2231 NXmonochromator node. This is a subclass of the NXgroup class. 2232 2233 See the NXgroup documentation for more details. 2234 """ 2235 def __init__(self, *items, **opts): 2236 self.nxclass = "NXmonochromator" 2237 NXgroup.__init__(self, *items, **opts) 2238 2239 2240 class NXpolarizer(NXgroup): 2241 """ 2242 NXpolarizer node. This is a subclass of the NXgroup class. 2243 2244 See the NXgroup documentation for more details. 2245 """ 2246 def __init__(self, *items, **opts): 2247 self.nxclass = "NXpolarizer" 2248 NXgroup.__init__(self, *items, **opts) 2249 2250 2251 class NXpositioner(NXgroup): 2252 """ 2253 NXpositioner node. This is a subclass of the NXgroup class. 2254 2255 See the NXgroup documentation for more details. 2256 """ 2257 def __init__(self, *items, **opts): 2258 self.nxclass = "NXpositioner" 2259 NXgroup.__init__(self, *items, **opts) 2260 2261 2262 class NXsource(NXgroup): 2263 """ 2264 NXsource node. This is a subclass of the NXgroup class. 2265 2266 See the NXgroup documentation for more details. 2267 """ 2268 def __init__(self, *items, **opts): 2269 self.nxclass = "NXsource" 2270 NXgroup.__init__(self, *items, **opts) 2271 2272 2273 class NXvelocity_selector(NXgroup): 2274 """ 2275 NXvelocity_selector node. This is a subclass of the NXgroup class. 2276 2277 See the NXgroup documentation for more details. 2278 """ 2279 def __init__(self, *items, **opts): 2280 self.nxclass = "NXvelocity_selector" 2281 NXgroup.__init__(self, *items, **opts) 2282 2283 2284 class NXevent_data(NXgroup): 2285 """ 2286 NXevent_data node. This is a subclass of the NXgroup class. 2287 2288 See the NXgroup documentation for more details. 2289 """ 2290 def __init__(self, *items, **opts): 2291 self.nxclass = "NXevent_data" 2292 NXgroup.__init__(self, *items, **opts) 2293 2294 2295 class NXuser(NXgroup): 2296 """ 2297 NXuser node. This is a subclass of the NXgroup class. 2298 2299 See the NXgroup documentation for more details. 2300 """ 2301 def __init__(self, *items, **opts): 2302 self.nxclass = "NXuser" 2303 NXgroup.__init__(self, *items, **opts) 2304 2305 2306 class NXparameter(NXgroup): 2307 """ 2308 NXparameter node. This is a subclass of the NXgroup class. 2309 2310 See the NXgroup documentation for more details. 2311 """ 2312 def __init__(self, *items, **opts): 2313 self.nxclass = "NXparameter" 2314 NXgroup.__init__(self, *items, **opts) 2315 2316 2317 class NXprocess(NXgroup): 2318 """ 2319 NXprocess node. This is a subclass of the NXgroup class. 2320 2321 See the NXgroup documentation for more details. 2322 """ 2323 def __init__(self, *items, **opts): 2324 self.nxclass = "NXprocess" 2325 NXgroup.__init__(self, *items, **opts) 2326 2327 2328 class NXcharacterization(NXgroup): 2329 """ 2330 NXcharacterization node. This is a subclass of the NXgroup class. 2331 2332 See the NXgroup documentation for more details. 2333 """ 2334 def __init__(self, *items, **opts): 2335 self.nxclass = "NXcharacterization" 2336 NXgroup.__init__(self, *items, **opts) 2740 self._class = "NXmonitor" 2741 if "name" not in opts.keys(): 2742 self._name = "monitor" 2337 2743 2338 2744 2339 2745 class NXlog(NXgroup): 2340 """ 2341 NXlog node. This is a subclass of the NXgroup class. 2746 2747 """ 2748 NXlog group. This is a subclass of the NXgroup class. 2342 2749 2343 2750 Methods 2344 2751 ------- 2345 nxplot(self, **opts)2752 plot(self, **opts) 2346 2753 Plot the logged values against the elapsed time. Valid 2347 2754 Matplotlib parameters, specifying markers, colors, etc, can be … … 2350 2757 See the NXgroup documentation for more details. 2351 2758 """ 2759 2352 2760 def __init__(self, *items, **opts): 2353 self. nxclass = "NXlog"2761 self._class = "NXlog" 2354 2762 NXgroup.__init__(self, *items, **opts) 2355 2763 2356 def nxplot(self, **opts):2764 def plot(self, **opts): 2357 2765 axis = [self.time] 2358 2766 title = "%s Log" % self.value.nxname.upper() … … 2360 2768 2361 2769 2362 2363 class NXnote(NXgroup): 2364 """ 2365 NXnote node. This is a subclass of the NXgroup class. 2366 2367 See the NXgroup documentation for more details. 2368 """ 2369 def __init__(self, *items, **opts): 2370 self.nxclass = "NXnote" 2371 NXgroup.__init__(self, *items, **opts) 2372 2373 2374 class NXbeam(NXgroup): 2375 """ 2376 NXbeam node. This is a subclass of the NXgroup class. 2377 2378 See the NXgroup documentation for more details. 2379 """ 2380 def __init__(self, *items, **opts): 2381 self.nxclass = "NXbeam" 2382 NXgroup.__init__(self, *items, **opts) 2383 2384 2385 class NXgeometry(NXgroup): 2386 """ 2387 NXgeometry node. This is a subclass of the NXgroup class. 2388 2389 See the NXgroup documentation for more details. 2390 """ 2391 def __init__(self, *items, **opts): 2392 self.nxclass = "NXgeometry" 2393 NXgroup.__init__(self, *items, **opts) 2394 2395 2396 class NXtranslation(NXgroup): 2397 """ 2398 NXtranslation node. This is a subclass of the NXgroup class. 2399 2400 See the NXgroup documentation for more details. 2401 """ 2402 def __init__(self, *items, **opts): 2403 self.nxclass = "NXtranslation" 2404 NXgroup.__init__(self, *items, **opts) 2405 2406 2407 class NXshape(NXgroup): 2408 """ 2409 NXshape node. This is a subclass of the NXgroup class. 2410 2411 See the NXgroup documentation for more details. 2412 """ 2413 def __init__(self, *items, **opts): 2414 self.nxclass = "NXshape" 2415 NXgroup.__init__(self, *items, **opts) 2416 2417 2418 class NXorientation(NXgroup): 2419 """ 2420 NXorientation node. This is a subclass of the NXgroup class. 2421 2422 See the NXgroup documentation for more details. 2423 """ 2424 def __init__(self, *items, **opts): 2425 self.nxclass = "NXorientation" 2426 NXgroup.__init__(self, *items, **opts) 2427 2428 2429 class NXenvironment(NXgroup): 2430 """ 2431 NXenvironment node. This is a subclass of the NXgroup class. 2432 2433 See the NXgroup documentation for more details. 2434 """ 2435 def __init__(self, *items, **opts): 2436 self.nxclass = "NXenvironment" 2437 NXgroup.__init__(self, *items, **opts) 2438 2439 2440 class NXsensor(NXgroup): 2441 """ 2442 NXsensor node. This is a subclass of the NXgroup class. 2443 2444 See the NXgroup documentation for more details. 2445 """ 2446 def __init__(self, *items, **opts): 2447 self.nxclass = "NXsensor" 2448 NXgroup.__init__(self, *items, **opts) 2449 2450 2451 class NXlink(NXnode): 2452 """ 2453 NeXus linked node. 2454 2455 The real node will be accessible by following the nxlink attribute. 2456 """ 2457 nxclass = "NXlink" 2458 2459 def __init__(self, target=None, name="link"): 2460 self.nxname = name 2461 self.nxgroup = None 2462 if isinstance(target, NXnode): 2463 self._target = target.nxpath 2464 if target.nxclass == "NXlink": 2465 raise NeXusError, "Cannot link to another NXlink object" 2466 elif target.nxclass == "SDS": 2467 self.__class__ = NXlinkdata 2468 else: 2469 self.__class__ = NXlinkgroup 2470 else: 2471 self._target = target 2472 2473 def __getattr__(self, key): 2474 try: 2475 if key == "nxdata": return self.nxlink.nxdata 2476 return self.nxlink.__dict__[key] 2477 except KeyError: 2478 raise KeyError, (key+" not in %s" % self._target) 2479 2480 def __repr__(self): 2481 return "NXlink('%s')"%(self._target) 2482 2483 def __str__(self): 2484 return "NXlink('%s')"%(self._target) 2485 2486 def _str_tree(self, indent=0, attrs=False, recursive=False): 2487 if self.nxlink: 2488 return self.nxlink._str_tree(indent, attrs, recursive) 2489 else: 2490 return " "*indent+self.nxname+' -> '+self._target 2491 2492 def _link(self): 2493 link = getRoot(self) 2494 if link: 2495 try: 2496 for level in self._target[1:].split('/'): 2497 link = getattr(link, level) 2498 return link 2499 except AttributeError: 2500 return None 2501 else: 2502 return None 2503 2504 def _attrs(self): 2505 return dict([(k,v) 2506 for k,v in self.nxlink.__dict__.items() 2507 if isinstance(v,NXattr)]) 2508 2509 def _entries(self): 2510 return dict([(k,v) 2511 for k,v in self.nxlink.__dict__.items() 2512 if isinstance(v,NXnode) and not k.startswith('nx') 2513 and not k.startswith('_')]) 2514 2515 nxlink = property(_link, "Linked object") 2516 nxattrs = property(_attrs,doc="NeXus attributes for node") 2517 nxentries = property(_entries,doc="NeXus nodes within group") 2518 2519 2520 class NXlinkdata(NXlink, SDS): 2521 """ 2522 NeXus linked SDS. 2523 2524 The real node will be accessible by following the nxlink attribute. 2525 """ 2526 def __setattr__(self, name, value): 2527 if name.startswith('_'): 2528 object.__setattr__(self, name, value) 2529 elif name == "nxname" or name == "nxclass" or name == "nxgroup": 2530 SDS.__setattr__(self, name, value) 2531 elif self.nxlink: 2532 self.nxlink.__setattr__(name, value) 2533 2534 def nxget(self, offset, size, units=""): 2535 """ 2536 Get a slab from the data array. 2537 2538 Offsets are 0-origin. Shape can be inferred from the data. 2539 Offset and shape must each have one entry per dimension. 2540 2541 If units are specified, convert the values to the given units 2542 before returning them. 2543 2544 This operation should be performed in a "with group.data" 2545 conext. 2546 2547 Raises ValueError cannot convert units. 2548 2549 Corresponds to NXgetslab(handle,data,offset,shape) 2550 """ 2551 self.nxlink.__enter__() 2552 value = self.nxlink._file.getslab(offset,size) 2553 return self.nxlink._converter(value,units) 2554 self.nxlink.__exit__() 2555 2556 class NXlinkgroup(NXlink, NXgroup): 2557 """ 2558 NeXus linked group. 2559 2560 The real node will be accessible by following the nxlink attribute. 2561 """ 2562 def __setattr__(self, name, value): 2563 if name.startswith('_'): 2564 object.__setattr__(self, name, value) 2565 elif name == "nxname" or name == "nxclass" or name == "nxgroup": 2566 NXgroup.__setattr__(self, name, value) 2567 elif self.nxlink: 2568 if not isinstance(value, NXnode): value = SDS(value=value, name=name) 2569 value.nxgroup = self 2570 value.nxname = name 2571 object.__setattr__(self, name, value) 2572 setattr(self.nxlink, name, value) 2573 2574 2575 class Unknown(NXnode): 2576 """ 2577 Unknown group type; class does not start with NX or SDS. 2578 """ 2579 def __init__(self, nxname="unknown", nxclass="unknown"): 2580 self.nxname = nxname 2581 self.nxclass = nxclass 2582 2583 def __repr__(self): 2584 return "Unknown('%s','%s')"%(self.nxname,self.nxclass) 2770 #------------------------------------------------------------------------- 2771 #Add remaining base classes as subclasses of NXgroup and append to __all__ 2772 2773 for _class in _nxclasses: 2774 if _class not in globals(): 2775 docstring = """ 2776 %s group. This is a subclass of the NXgroup class. 2777 2778 See the NXgroup documentation for more details. 2779 """ % _class 2780 globals()[_class]=type(_class, (NXgroup,), 2781 {'_class':_class,'__doc__':docstring}) 2782 __all__.append(_class) 2783 2784 #------------------------------------------------------------------------- 2585 2785 2586 2786 2587 2787 def centers(signal, axes): 2588 2788 """ 2589 Return the centers of the axes regardless if the axes contain 2590 bin boundaries or centers. 2789 Return the centers of the axes. 2790 2791 This works regardless if the axes contain bin boundaries or centers. 2591 2792 """ 2592 2793 def findc(axis, dimlen): 2593 if axis. nxdims[0] == dimlen+1:2794 if axis.shape[0] == dimlen+1: 2594 2795 return (axis.nxdata[:-1] + axis.nxdata[1:])/2 2595 2796 else: 2596 assert axis. nxdims[0] == dimlen2797 assert axis.shape[0] == dimlen 2597 2798 return axis.nxdata 2598 return [findc(a,signal.nxdims[i]) for i,a in enumerate(axes)] 2799 return [findc(a,signal.shape[i]) for i,a in enumerate(axes)] 2800 2801 def setmemory(value): 2802 """ 2803 Set the memory limit for data arrays (in MB). 2804 """ 2805 global NX_MEMORY 2806 NX_MEMORY = value 2599 2807 2600 2808 def label(field): 2601 2809 """ 2602 Constructa label for a data field suitable for use on a graph axis.2810 Return a label for a data field suitable for use on a graph axis. 2603 2811 """ 2604 2812 if hasattr(field,'long_name'): 2605 return field.long_name .nxdata2813 return field.long_name 2606 2814 elif hasattr(field,'units'): 2607 return "%s (%s)"%(field.nxname,field.units .nxdata)2815 return "%s (%s)"%(field.nxname,field.units) 2608 2816 else: 2609 2817 return field.nxname … … 2611 2819 def imshow_irregular(x,y,z): 2612 2820 import pylab 2613 #from matplotlib.ticker import FormatStrFormatter2821 # from matplotlib.ticker import LogFormatter 2614 2822 ax = pylab.gca() 2615 2823 im = pylab.mpl.image.NonUniformImage(ax, extent=(x[0],x[-1],y[0],y[-1]), origin=None) … … 2618 2826 ax.set_xlim(x[0],x[-1]) 2619 2827 ax.set_ylim(y[0],y[-1]) 2620 pylab.colorbar(im) #format=FormatStrFormatter('$10^{%d}$')2828 pylab.colorbar(im)#, format=LogFormatter()) 2621 2829 pylab.gcf().canvas.draw_idle() 2622 2830 … … 2624 2832 def load(filename, mode='r'): 2625 2833 """ 2626 Read a NeXus file, returning a tree of nodes 2834 Read a NeXus file returning a tree of objects. 2835 2836 This is aliased to 'read' because of potential name clashes with Numpy 2627 2837 """ 2628 2838 file = NeXusTree(filename,mode) … … 2631 2841 return tree 2632 2842 2633 def save(filename, node, format='w5'): 2634 """ 2635 Write a NeXus file from a tree of nodes 2636 """ 2637 if node.nxclass == "NXroot": 2638 tree = node 2639 elif node.nxclass == "NXentry": 2640 tree = NXroot(node) 2843 #Definition for when there are name clashes with Numpy 2844 read = load 2845 __all__.append('read') 2846 2847 def save(filename, group, format='w5'): 2848 """ 2849 Write a NeXus file from a tree of objects. 2850 """ 2851 if group.nxclass == "NXroot": 2852 tree = group 2853 elif group.nxclass == "NXentry": 2854 tree = NXroot(group) 2641 2855 else: 2642 tree = NXroot(NXentry( node))2856 tree = NXroot(NXentry(group)) 2643 2857 file = NeXusTree(filename, format) 2644 2858 file.writefile(tree) … … 2647 2861 def tree(file): 2648 2862 """ 2649 Read and summarize the named nexus file.2863 Read and summarize the named NeXus file. 2650 2864 """ 2651 2865 nxfile = load(file) 2652 nxfile. nxtree()2866 nxfile.tree 2653 2867 2654 2868 def demo(argv): 2655 2869 """ 2656 Process command line commands in argv. argv should contain 2657 program name, command, arguments, where command is one of 2658 the following: 2870 Process a list of command line commands. 2871 2872 'argv' should contain program name, command, arguments, where command is one 2873 of the following: 2659 2874 copy fromfile.nxs tofile.nxs 2660 2875 ls f1.nxs f2.nxs ... … … 2673 2888 for entry in argv[3].split('.'): 2674 2889 tree = getattr(tree,entry) 2675 tree. nxplot()2890 tree.plot() 2676 2891 tree._plotter.show() 2677 2892 … … 2684 2899 """%(argv[0],) 2685 2900 print usage 2901 2686 2902 2687 2903 if __name__ == "__main__":
Note: See TracChangeset
for help on using the changeset viewer.
