ChessAnalysisPipeline 0.0.11__py3-none-any.whl → 0.0.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ChessAnalysisPipeline might be problematic. Click here for more details.

CHAP/common/processor.py CHANGED
@@ -8,19 +8,84 @@ Description: Module for Processors used in multiple experiment-specific
8
8
  workflows.
9
9
  """
10
10
 
11
- # system modules
12
- from json import dumps
13
- from time import time
11
+ # Third party modules
12
+ import numpy as np
14
13
 
15
- # local modules
14
+ # Local modules
16
15
  from CHAP import Processor
17
16
 
18
17
 
18
+ class AnimationProcessor(Processor):
19
+ """A Processor to show and return an animation.
20
+ """
21
+ def process(
22
+ self, data, num_frames, axis=0, interval=1000, blit=True,
23
+ repeat=True, repeat_delay=1000):
24
+ """Show and return an animation of image slices from a dataset
25
+ contained in `data`.
26
+
27
+ :param data: Input data.
28
+ :type data: CHAP.pipeline.PipelineData
29
+ :param num_frames: Number of frames for the animation.
30
+ :type num_frames: int
31
+ :param axis: Axis direction of the image slices,
32
+ defaults to `0`
33
+ :type axis: int, optional
34
+ :param interval: Delay between frames in milliseconds,
35
+ defaults to `1000`
36
+ :type interval: int, optional
37
+ :param blit: Whether blitting is used to optimize drawing,
38
+ default to `True`
39
+ :type blit: bool, optional
40
+ :param repeat: Whether the animation repeats when the sequence
41
+ of frames is completed, defaults to `True`
42
+ :type repeat: bool, optional
43
+ :param repeat_delay: Delay in milliseconds between consecutive
44
+ animation runs if repeat is `True`, defaults to `1000`
45
+ :type repeat_delay: int, optional
46
+ :return: The matplotlib animation.
47
+ :rtype: matplotlib.animation.ArtistAnimation
48
+ """
49
+ # Third party modules
50
+ import matplotlib.animation as animation
51
+ import matplotlib.pyplot as plt
52
+
53
+ # Get the frames
54
+ data = self.unwrap_pipelinedata(data)[-1]
55
+ delta = int(data.shape[axis]/(num_frames+1))
56
+ indices = np.linspace(delta, data.shape[axis]-delta, num_frames)
57
+ if data.ndim == 3:
58
+ if not axis:
59
+ frames = [data[int(index)] for index in indices]
60
+ elif axis == 1:
61
+ frames = [data[:,int(index),:] for index in indices]
62
+ elif axis == 2:
63
+ frames = [data[:,:,int(index)] for index in indices]
64
+ else:
65
+ raise ValueError('Invalid data dimension (must be 2D or 3D)')
66
+
67
+ fig = plt.figure()
68
+ # vmin = np.min(frames)/8
69
+ # vmax = np.max(frames)/8
70
+ ims = [[plt.imshow(
71
+ #frames[n], vmin=vmin,vmax=vmax, cmap='gray',
72
+ frames[n], cmap='gray',
73
+ animated=True)]
74
+ for n in range(num_frames)]
75
+ ani = animation.ArtistAnimation(
76
+ fig, ims, interval=interval, blit=blit, repeat=repeat,
77
+ repeat_delay=repeat_delay)
78
+
79
+ plt.show()
80
+
81
+ return ani
82
+
83
+
19
84
  class AsyncProcessor(Processor):
20
85
  """A Processor to process multiple sets of input data via asyncio
21
- module
86
+ module.
22
87
 
23
- :ivar mgr: The `Processor` used to process every set of input data
88
+ :ivar mgr: The `Processor` used to process every set of input data.
24
89
  :type mgr: Processor
25
90
  """
26
91
  def __init__(self, mgr):
@@ -31,31 +96,31 @@ class AsyncProcessor(Processor):
31
96
  """Asynchronously process the input documents with the
32
97
  `self.mgr` `Processor`.
33
98
 
34
- :param data: input data documents to process
99
+ :param data: Input data documents to process.
35
100
  :type docs: iterable
36
101
  """
37
-
102
+ # System modules
38
103
  import asyncio
39
104
 
40
105
  async def task(mgr, doc):
41
- """Process given data using provided `Processor`
106
+ """Process given data using provided `Processor`.
42
107
 
43
- :param mgr: the object that will process given data
108
+ :param mgr: The object that will process given data.
44
109
  :type mgr: Processor
45
- :param doc: the data to process
110
+ :param doc: The data to process.
46
111
  :type doc: object
47
- :return: processed data
112
+ :return: The processed data.
48
113
  :rtype: object
49
114
  """
50
115
  return mgr.process(doc)
51
116
 
52
117
  async def execute_tasks(mgr, docs):
53
118
  """Process given set of documents using provided task
54
- manager
119
+ manager.
55
120
 
56
- :param mgr: the object that will process all documents
121
+ :param mgr: The object that will process all documents.
57
122
  :type mgr: Processor
58
- :param docs: the set of data documents to process
123
+ :param docs: The set of data documents to process.
59
124
  :type doc: iterable
60
125
  """
61
126
  coroutines = [task(mgr, d) for d in docs]
@@ -64,22 +129,56 @@ class AsyncProcessor(Processor):
64
129
  asyncio.run(execute_tasks(self.mgr, data))
65
130
 
66
131
 
67
- class IntegrationProcessor(Processor):
68
- """A processor for integrating 2D data with pyFAI"""
132
+ class ImageProcessor(Processor):
133
+ """A Processor to plot an image slice from a dataset.
134
+ """
135
+ def process(self, data, index=0, axis=0):
136
+ """Plot an image from a dataset contained in `data` and return
137
+ the full dataset.
138
+
139
+ :param data: Input data.
140
+ :type data: CHAP.pipeline.PipelineData
141
+ :param index: Array index of the slice of data to plot,
142
+ defaults to `0`
143
+ :type index: int, optional
144
+ :param axis: Axis direction of the image slice,
145
+ defaults to `0`
146
+ :type axis: int, optional
147
+ :return: The full input dataset.
148
+ :rtype: object
149
+ """
150
+ # Local modules
151
+ from CHAP.utils.general import quick_imshow
152
+
153
+ data = self.unwrap_pipelinedata(data)[0]
154
+ if data.ndim == 2:
155
+ quick_imshow(data, block=True)
156
+ elif data.ndim == 3:
157
+ if not axis:
158
+ quick_imshow(data[index], block=True)
159
+ elif axis == 1:
160
+ quick_imshow(data[:,index,:], block=True)
161
+ elif axis == 2:
162
+ quick_imshow(data[:,:,index], block=True)
163
+ else:
164
+ raise ValueError(f'Invalid parameter axis ({axis})')
165
+ else:
166
+ raise ValueError('Invalid data dimension (must be 2D or 3D)')
167
+
168
+ return data
69
169
 
170
+
171
+ class IntegrationProcessor(Processor):
172
+ """A processor for integrating 2D data with pyFAI.
173
+ """
70
174
  def process(self, data):
71
175
  """Integrate the input data with the integration method and
72
- keyword arguments supplied and return the results.
176
+ keyword arguments supplied in `data` and return the results.
73
177
 
74
- :param data: input data, including raw data, integration
178
+ :param data: Input data, containing the raw data, integration
75
179
  method, and keyword args for the integration method.
76
- :type data: tuple[typing.Union[numpy.ndarray,
77
- list[numpy.ndarray]], callable, dict]
78
- :param integration_method: the method of a
79
- `pyFAI.azimuthalIntegrator.AzimuthalIntegrator` or
80
- `pyFAI.multi_geometry.MultiGeometry` that returns the
81
- desired integration results.
82
- :return: integrated raw data
180
+ :type data: CHAP.pipeline.PipelineData
181
+ :return: Integrated raw data.
83
182
  :rtype: pyFAI.containers.IntegrateResult
84
183
  """
85
184
  detector_data, integration_method, integration_kwargs = data
@@ -88,26 +187,23 @@ class IntegrationProcessor(Processor):
88
187
 
89
188
 
90
189
  class IntegrateMapProcessor(Processor):
91
- """Class representing a process that takes a map and integration
92
- configuration and returns a `nexusformat.nexus.NXprocess`
93
- containing a map of the integrated detector data requested.
190
+ """A processor that takes a map and integration configuration and
191
+ returns a NeXus NXprocesss object containing a map of the
192
+ integrated detector data requested.
94
193
  """
95
-
96
194
  def process(self, data):
97
195
  """Process the output of a `Reader` that contains a map and
98
- integration configuration and return a
99
- `nexusformat.nexus.NXprocess` containing a map of the
100
- integrated detector data requested
196
+ integration configuration and return a NeXus NXprocess object
197
+ containing a map of the integrated detector data requested.
101
198
 
102
- :param data: Result of `Reader.read` where at least one item
103
- has the value `'MapConfig'` for the `'schema'` key, and at
104
- least one item has the value `'IntegrationConfig'` for the
199
+ :param data: Input data, containing at least one item
200
+ with the value `'MapConfig'` for the `'schema'` key, and at
201
+ least one item with the value `'IntegrationConfig'` for the
105
202
  `'schema'` key.
106
- :type data: list[dict[str,object]]
107
- :return: integrated data and process metadata
203
+ :type data: CHAP.pipeline.PipelineData
204
+ :return: Integrated data and process metadata.
108
205
  :rtype: nexusformat.nexus.NXprocess
109
206
  """
110
-
111
207
  map_config = self.get_config(
112
208
  data, 'common.models.map.MapConfig')
113
209
  integration_config = self.get_config(
@@ -118,27 +214,31 @@ class IntegrateMapProcessor(Processor):
118
214
 
119
215
  def get_nxprocess(self, map_config, integration_config):
120
216
  """Use a `MapConfig` and `IntegrationConfig` to construct a
121
- `nexusformat.nexus.NXprocess`
217
+ NeXus NXprocess object.
122
218
 
123
- :param map_config: a valid map configuration
219
+ :param map_config: A valid map configuration.
124
220
  :type map_config: MapConfig
125
- :param integration_config: a valid integration configuration
126
- :type integration_config: IntegrationConfig
127
- :return: the integrated detector data and metadata contained
128
- in a NeXus structure
221
+ :param integration_config: A valid integration configuration
222
+ :type integration_config: IntegrationConfig.
223
+ :return: The integrated detector data and metadata.
129
224
  :rtype: nexusformat.nexus.NXprocess
130
225
  """
226
+ # System modules
227
+ from json import dumps
228
+ from time import time
229
+
230
+ # Third party modules
231
+ from nexusformat.nexus import (
232
+ NXdata,
233
+ NXdetector,
234
+ NXfield,
235
+ NXprocess,
236
+ )
237
+ import pyFAI
131
238
 
132
239
  self.logger.debug('Constructing NXprocess')
133
240
  t0 = time()
134
241
 
135
- from nexusformat.nexus import (NXdata,
136
- NXdetector,
137
- NXfield,
138
- NXprocess)
139
- import numpy as np
140
- import pyFAI
141
-
142
242
  nxprocess = NXprocess(name=integration_config.title)
143
243
 
144
244
  nxprocess.map_config = dumps(map_config.dict())
@@ -255,24 +355,21 @@ class IntegrateMapProcessor(Processor):
255
355
 
256
356
 
257
357
  class MapProcessor(Processor):
258
- """A Processor to take a map configuration and return a
259
- `nexusformat.nexus.NXentry` representing that map's metadata and
260
- any scalar-valued raw data requseted by the supplied map
261
- configuration.
358
+ """A Processor that takes a map configuration and returns a NeXus
359
+ NXentry object representing that map's metadata and any
360
+ scalar-valued raw data requested by the supplied map configuration.
262
361
  """
263
-
264
362
  def process(self, data):
265
363
  """Process the output of a `Reader` that contains a map
266
- configuration and return a `nexusformat.nexus.NXentry`
267
- representing the map.
364
+ configuration and returns a NeXus NXentry object representing
365
+ the map.
268
366
 
269
367
  :param data: Result of `Reader.read` where at least one item
270
368
  has the value `'MapConfig'` for the `'schema'` key.
271
- :type data: list[dict[str,object]]
272
- :return: Map data & metadata
369
+ :type data: CHAP.pipeline.PipelineData
370
+ :return: Map data and metadata.
273
371
  :rtype: nexusformat.nexus.NXentry
274
372
  """
275
-
276
373
  map_config = self.get_config(data, 'common.models.map.MapConfig')
277
374
  nxentry = self.__class__.get_nxentry(map_config)
278
375
 
@@ -280,29 +377,29 @@ class MapProcessor(Processor):
280
377
 
281
378
  @staticmethod
282
379
  def get_nxentry(map_config):
283
- """Use a `MapConfig` to construct a
284
- `nexusformat.nexus.NXentry`
380
+ """Use a `MapConfig` to construct a NeXus NXentry object.
285
381
 
286
- :param map_config: a valid map configuration
382
+ :param map_config: A valid map configuration.
287
383
  :type map_config: MapConfig
288
- :return: the map's data and metadata contained in a NeXus
289
- structure
384
+ :return: The map's data and metadata contained in a NeXus
385
+ structure.
290
386
  :rtype: nexusformat.nexus.NXentry
291
387
  """
292
-
293
- from nexusformat.nexus import (NXcollection,
294
- NXdata,
295
- NXentry,
296
- NXfield,
297
- NXsample)
298
- import numpy as np
388
+ # System modules
389
+ from json import dumps
390
+
391
+ # Third party modules
392
+ from nexusformat.nexus import (
393
+ NXcollection,
394
+ NXdata,
395
+ NXentry,
396
+ NXfield,
397
+ NXsample,
398
+ )
299
399
 
300
400
  nxentry = NXentry(name=map_config.title)
301
-
302
401
  nxentry.map_config = dumps(map_config.dict())
303
-
304
402
  nxentry[map_config.sample.name] = NXsample(**map_config.sample.dict())
305
-
306
403
  nxentry.attrs['station'] = map_config.station
307
404
 
308
405
  nxentry.spec_scans = NXcollection()
@@ -313,7 +410,8 @@ class MapProcessor(Processor):
313
410
  attrs={'spec_file': str(scans.spec_file)})
314
411
 
315
412
  nxentry.data = NXdata()
316
- nxentry.data.attrs['axes'] = map_config.dims
413
+ if map_config.map_type == 'structured':
414
+ nxentry.data.attrs['axes'] = map_config.dims
317
415
  for i, dim in enumerate(map_config.independent_dimensions[::-1]):
318
416
  nxentry.data[dim.label] = NXfield(
319
417
  value=map_config.coords[dim.label],
@@ -321,7 +419,8 @@ class MapProcessor(Processor):
321
419
  attrs={'long_name': f'{dim.label} ({dim.units})',
322
420
  'data_type': dim.data_type,
323
421
  'local_name': dim.name})
324
- nxentry.data.attrs[f'{dim.label}_indices'] = i
422
+ if map_config.map_type == 'structured':
423
+ nxentry.data.attrs[f'{dim.label}_indices'] = i
325
424
 
326
425
  signal = False
327
426
  auxilliary_signals = []
@@ -350,22 +449,21 @@ class MapProcessor(Processor):
350
449
 
351
450
 
352
451
  class NexusToNumpyProcessor(Processor):
353
- """A Processor to convert the default plottable data in an
354
- `NXobject` into an `numpy.ndarray`.
452
+ """A Processor to convert the default plottable data in a NeXus
453
+ object into a `numpy.ndarray`.
355
454
  """
356
-
357
455
  def process(self, data):
358
- """Return the default plottable data signal in `data` as an
359
- `numpy.ndarray`.
360
-
361
- :param data: input NeXus structure
362
- :type data: nexusformat.nexus.tree.NXobject
363
- :raises ValueError: if `data` has no default plottable data
364
- signal
365
- :return: default plottable data signal in `data`
456
+ """Return the default plottable data signal in a NeXus object
457
+ contained in `data` as an `numpy.ndarray`.
458
+
459
+ :param data: Input data.
460
+ :type data: nexusformat.nexus.NXobject
461
+ :raises ValueError: If `data` has no default plottable data
462
+ signal.
463
+ :return: The default plottable data signal.
366
464
  :rtype: numpy.ndarray
367
465
  """
368
-
466
+ # Third party modules
369
467
  from nexusformat.nexus import NXdata
370
468
 
371
469
  data = self.unwrap_pipelinedata(data)[-1]
@@ -392,22 +490,21 @@ class NexusToNumpyProcessor(Processor):
392
490
 
393
491
 
394
492
  class NexusToXarrayProcessor(Processor):
395
- """A Processor to convert the default plottable data in an
396
- `NXobject` into an `xarray.DataArray`.
493
+ """A Processor to convert the default plottable data in a
494
+ NeXus object into an `xarray.DataArray`.
397
495
  """
398
-
399
496
  def process(self, data):
400
- """Return the default plottable data signal in `data` as an
401
- `xarray.DataArray`.
497
+ """Return the default plottable data signal in a NeXus object
498
+ contained in `data` as an `xarray.DataArray`.
402
499
 
403
- :param data: input NeXus structure
404
- :type data: nexusformat.nexus.tree.NXobject
405
- :raises ValueError: if metadata for `xarray` is absent from
500
+ :param data: Input data.
501
+ :type data: nexusformat.nexus.NXobject
502
+ :raises ValueError: If metadata for `xarray` is absent from
406
503
  `data`
407
- :return: default plottable data signal in `data`
504
+ :return: The default plottable data signal.
408
505
  :rtype: xarray.DataArray
409
506
  """
410
-
507
+ # Third party modules
411
508
  from nexusformat.nexus import NXdata
412
509
  from xarray import DataArray
413
510
 
@@ -456,18 +553,15 @@ class PrintProcessor(Processor):
456
553
  """A Processor to simply print the input data to stdout and return
457
554
  the original input data, unchanged in any way.
458
555
  """
459
-
460
556
  def process(self, data):
461
557
  """Print and return the input data.
462
558
 
463
- :param data: Input data
559
+ :param data: Input data.
464
560
  :type data: object
465
561
  :return: `data`
466
562
  :rtype: object
467
563
  """
468
-
469
564
  print(f'{self.__name__} data :')
470
-
471
565
  if callable(getattr(data, '_str_tree', None)):
472
566
  # If data is likely an NXobject, print its tree
473
567
  # representation (since NXobjects' str representations are
@@ -480,23 +574,23 @@ class PrintProcessor(Processor):
480
574
 
481
575
 
482
576
  class RawDetectorDataMapProcessor(Processor):
483
- """A Processor to return a map of raw derector data in an NXroot"""
484
-
577
+ """A Processor to return a map of raw derector data in a
578
+ NeXus NXroot object.
579
+ """
485
580
  def process(self, data, detector_name, detector_shape):
486
581
  """Process configurations for a map and return the raw
487
582
  detector data data collected over the map.
488
583
 
489
- :param data: input map configuration
490
- :type data: list[dict[str,object]]
491
- :param detector_name: detector prefix
584
+ :param data: Input map configuration.
585
+ :type data: CHAP.pipeline.PipelineData
586
+ :param detector_name: The detector prefix.
492
587
  :type detector_name: str
493
- :param detector_shape: shape of detector data for a single
494
- scan step
588
+ :param detector_shape: The shape of detector data for a single
589
+ scan step.
495
590
  :type detector_shape: list
496
- :return: map of raw detector data
591
+ :return: Map of raw detector data.
497
592
  :rtype: nexusformat.nexus.NXroot
498
593
  """
499
-
500
594
  map_config = self.get_config(data)
501
595
  nxroot = self.get_nxroot(map_config, detector_name, detector_shape)
502
596
 
@@ -504,17 +598,18 @@ class RawDetectorDataMapProcessor(Processor):
504
598
 
505
599
  def get_config(self, data):
506
600
  """Get instances of the map configuration object needed by this
507
- `Processor`
601
+ `Processor`.
508
602
 
509
603
  :param data: Result of `Reader.read` where at least one item
510
- has the value `'MapConfig'` for the `'schema'` key
511
- :type data: list[dict[str,object]]
604
+ has the value `'MapConfig'` for the `'schema'` key.
605
+ :type data: CHAP.pipeline.PipelineData
512
606
  :raises Exception: If a valid map config object cannot be
513
607
  constructed from `data`.
514
- :return: valid instances of the map configuration object with
608
+ :return: A valid instance of the map configuration object with
515
609
  field values taken from `data`.
516
610
  :rtype: MapConfig
517
611
  """
612
+ # Local modules
518
613
  from CHAP.common.models.map import MapConfig
519
614
 
520
615
  map_config = False
@@ -532,27 +627,28 @@ class RawDetectorDataMapProcessor(Processor):
532
627
 
533
628
  def get_nxroot(self, map_config, detector_name, detector_shape):
534
629
  """Get a map of the detector data collected by the scans in
535
- `map_config`.The data will be returned along with some
630
+ `map_config`. The data will be returned along with some
536
631
  relevant metadata in the form of a NeXus structure.
537
632
 
538
- :param map_config: the map configuration
633
+ :param map_config: The map configuration.
539
634
  :type map_config: MapConfig
540
- :param detector_name: detector prefix
635
+ :param detector_name: The detector prefix.
541
636
  :type detector_name: str
542
- :param detector_shape: shape of detector data for a single
543
- scan step
637
+ :param detector_shape: The shape of detector data for a single
638
+ scan step.
544
639
  :type detector_shape: list
545
- :return: a map of the raw detector data
640
+ :return: A map of the raw detector data.
546
641
  :rtype: nexusformat.nexus.NXroot
547
642
  """
548
- # third party modules
549
- from nexusformat.nexus import (NXdata,
550
- NXdetector,
551
- NXinstrument,
552
- NXroot)
553
- import numpy as np
554
-
555
- # local modules
643
+ # Third party modules
644
+ from nexusformat.nexus import (
645
+ NXdata,
646
+ NXdetector,
647
+ NXinstrument,
648
+ NXroot,
649
+ )
650
+
651
+ # Local modules
556
652
  from CHAP.common import MapProcessor
557
653
 
558
654
  nxroot = NXroot()
@@ -602,42 +698,39 @@ class RawDetectorDataMapProcessor(Processor):
602
698
 
603
699
 
604
700
  class StrainAnalysisProcessor(Processor):
605
- """A Processor to compute a map of sample strains by fitting bragg
701
+ """A Processor to compute a map of sample strains by fitting Bragg
606
702
  peaks in 1D detector data and analyzing the difference between
607
703
  measured peak locations and expected peak locations for the sample
608
704
  measured.
609
705
  """
610
-
611
706
  def process(self, data):
612
707
  """Process the input map detector data & configuration for the
613
708
  strain analysis procedure, and return a map of sample strains.
614
709
 
615
- :param data: results of `MutlipleReader.read` containing input
710
+ :param data: Results of `MutlipleReader.read` containing input
616
711
  map detector data and strain analysis configuration
617
- :type data: dict[list[str,object]]
618
- :return: map of sample strains
712
+ :type data: CHAP.pipeline.PipelineData
713
+ :return: A map of sample strains.
619
714
  :rtype: xarray.Dataset
620
715
  """
621
-
622
716
  strain_analysis_config = self.get_config(data)
623
717
 
624
718
  return data
625
719
 
626
720
  def get_config(self, data):
627
721
  """Get instances of the configuration objects needed by this
628
- `Processor` from a returned value of `Reader.read`
722
+ `Processor`.
629
723
 
630
724
  :param data: Result of `Reader.read` where at least one item
631
725
  has the value `'StrainAnalysisConfig'` for the `'schema'`
632
726
  key.
633
- :type data: list[dict[str,object]]
727
+ :type data: CHAP.pipeline.PipelineData
634
728
  :raises Exception: If valid config objects cannot be
635
729
  constructed from `data`.
636
- :return: valid instances of the configuration objects with
730
+ :return: A valid instance of the configuration object with
637
731
  field values taken from `data`.
638
732
  :rtype: StrainAnalysisConfig
639
733
  """
640
-
641
734
  strain_analysis_config = False
642
735
  if isinstance(data, list):
643
736
  for item in data:
@@ -653,25 +746,25 @@ class StrainAnalysisProcessor(Processor):
653
746
 
654
747
 
655
748
  class XarrayToNexusProcessor(Processor):
656
- """A Processor to convert the data in an `xarray` structure to an
657
- `nexusformat.nexus.NXdata`.
749
+ """A Processor to convert the data in an `xarray` structure to a
750
+ NeXus NXdata object.
658
751
  """
659
-
660
752
  def process(self, data):
661
- """Return `data` represented as an `nexusformat.nexus.NXdata`.
753
+ """Return `data` represented as a NeXus NXdata object.
662
754
 
663
- :param data: The input `xarray` structure
755
+ :param data: The input `xarray` structure.
664
756
  :type data: typing.Union[xarray.DataArray, xarray.Dataset]
665
- :return: The data and metadata in `data`
757
+ :return: The data and metadata in `data`.
666
758
  :rtype: nexusformat.nexus.NXdata
667
759
  """
668
-
669
- from nexusformat.nexus import NXdata, NXfield
760
+ # Third party modules
761
+ from nexusformat.nexus import (
762
+ NXdata,
763
+ NXfield,
764
+ )
670
765
 
671
766
  data = self.unwrap_pipelinedata(data)[-1]
672
-
673
767
  signal = NXfield(value=data.data, name=data.name, attrs=data.attrs)
674
-
675
768
  axes = []
676
769
  for name, coord in data.coords.items():
677
770
  axes.append(
@@ -685,13 +778,12 @@ class XarrayToNumpyProcessor(Processor):
685
778
  """A Processor to convert the data in an `xarray.DataArray`
686
779
  structure to an `numpy.ndarray`.
687
780
  """
688
-
689
781
  def process(self, data):
690
782
  """Return just the signal values contained in `data`.
691
783
 
692
- :param data: The input `xarray.DataArray`
784
+ :param data: The input `xarray.DataArray`.
693
785
  :type data: xarray.DataArray
694
- :return: The data in `data`
786
+ :return: The data in `data`.
695
787
  :rtype: numpy.ndarray
696
788
  """
697
789
 
@@ -699,5 +791,7 @@ class XarrayToNumpyProcessor(Processor):
699
791
 
700
792
 
701
793
  if __name__ == '__main__':
794
+ # Local modules
702
795
  from CHAP.processor import main
796
+
703
797
  main()