nmrglue-ng 1.0.0__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.
- nmrglue/__init__.py +6 -0
- nmrglue/analysis/__init__.py +8 -0
- nmrglue/analysis/analysisbase.py +387 -0
- nmrglue/analysis/helpers.py +58 -0
- nmrglue/analysis/integration.py +207 -0
- nmrglue/analysis/leastsqbound.py +342 -0
- nmrglue/analysis/linesh.py +809 -0
- nmrglue/analysis/lineshapes1d.py +603 -0
- nmrglue/analysis/peakpick.py +561 -0
- nmrglue/analysis/segmentation.py +563 -0
- nmrglue/fileio/__init__.py +16 -0
- nmrglue/fileio/bruker.py +2911 -0
- nmrglue/fileio/convert.py +618 -0
- nmrglue/fileio/fileiobase.py +797 -0
- nmrglue/fileio/glue.py +254 -0
- nmrglue/fileio/jcampdx.py +1148 -0
- nmrglue/fileio/jeol.py +768 -0
- nmrglue/fileio/nmrml.py +81 -0
- nmrglue/fileio/pipe.py +2613 -0
- nmrglue/fileio/rnmrtk.py +819 -0
- nmrglue/fileio/rs2d.py +256 -0
- nmrglue/fileio/simpson.py +407 -0
- nmrglue/fileio/sparky.py +1751 -0
- nmrglue/fileio/spinsolve.py +306 -0
- nmrglue/fileio/table.py +429 -0
- nmrglue/fileio/tecmag.py +535 -0
- nmrglue/fileio/varian.py +2112 -0
- nmrglue/process/__init__.py +5 -0
- nmrglue/process/nmrtxt/__init__.py +1 -0
- nmrglue/process/nmrtxt/rance_kay.py +38 -0
- nmrglue/process/pipe_proc.py +3328 -0
- nmrglue/process/proc_autophase.py +286 -0
- nmrglue/process/proc_base.py +2780 -0
- nmrglue/process/proc_bl.py +424 -0
- nmrglue/process/proc_lp.py +1210 -0
- nmrglue/util/__init__.py +1 -0
- nmrglue/util/misc.py +212 -0
- nmrglue/util/xcpy.py +469 -0
- nmrglue/util/xcpy_test.py +31 -0
- nmrglue_ng-1.0.0.dist-info/METADATA +224 -0
- nmrglue_ng-1.0.0.dist-info/RECORD +44 -0
- nmrglue_ng-1.0.0.dist-info/WHEEL +5 -0
- nmrglue_ng-1.0.0.dist-info/licenses/LICENSE.txt +38 -0
- nmrglue_ng-1.0.0.dist-info/top_level.txt +1 -0
nmrglue/__init__.py
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
"""
|
|
2
|
+
analysisbase provides general purpose analysis functions and classes used by
|
|
3
|
+
several nmrglue.analysis modules
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
pi = np.pi
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# helper functions
|
|
12
|
+
def neighbors(pt, shape, structure):
|
|
13
|
+
"""
|
|
14
|
+
Generate a list of all neighbors to a point.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
pt : tuple of ints
|
|
19
|
+
Index of the point to find neighbors of.
|
|
20
|
+
shape : tuple of ints
|
|
21
|
+
Shape of the region.
|
|
22
|
+
structure : ndarray of bools
|
|
23
|
+
Structure element that defines connections.
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
pts : list of int tuples
|
|
28
|
+
List of tuples which represent indices for all points neighboring pt.
|
|
29
|
+
Edges are treated as stopping points.
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
# set middle of structure to False
|
|
33
|
+
s = np.copy(structure) # copy structure
|
|
34
|
+
middle = [int(np.floor(i / 2.)) for i in s.shape] # find middle
|
|
35
|
+
s.flat[np.ravel_multi_index(middle, s.shape)] = False
|
|
36
|
+
offsets = np.argwhere(s) - middle
|
|
37
|
+
|
|
38
|
+
# loop over the offset adding all valid points
|
|
39
|
+
pts = []
|
|
40
|
+
for offset in offsets:
|
|
41
|
+
npt = pt - offset
|
|
42
|
+
if valid_pt(npt, shape):
|
|
43
|
+
pts.append(tuple(npt))
|
|
44
|
+
return pts
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def valid_pt(pt, shape):
|
|
48
|
+
"""
|
|
49
|
+
Determine if a point (indices) is valid for a given shaped
|
|
50
|
+
"""
|
|
51
|
+
for i, j in zip(pt, shape):
|
|
52
|
+
if i < 0: # index is not negative
|
|
53
|
+
return False
|
|
54
|
+
if i >= j: # index is less than j
|
|
55
|
+
return False
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
dimension_names = ['A', 'Z', 'Y', 'X']
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# utility functions
|
|
62
|
+
def find_limits(pts):
|
|
63
|
+
"""
|
|
64
|
+
Find the limits which outline the provided list of points
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
pts : list of int tuples
|
|
69
|
+
List of points [(z0, y0, x0), (z1, y1, x1), ...]
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
min : ndarray
|
|
74
|
+
Array of minimum indices: array([zmin, ymin, xmin]
|
|
75
|
+
max : ndarray
|
|
76
|
+
Array of maximum indices: array([zmin, ymin, xmin]
|
|
77
|
+
|
|
78
|
+
See Also
|
|
79
|
+
--------
|
|
80
|
+
limits2slice : Create a list of slices from min, max limits
|
|
81
|
+
|
|
82
|
+
"""
|
|
83
|
+
arr_pts = np.array(pts)
|
|
84
|
+
return np.min(arr_pts, 0), np.max(arr_pts, 0)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def limits2slice(limits):
|
|
88
|
+
"""
|
|
89
|
+
Create a set of slice objects given an array of min, max limits.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
limits: tuple, (ndarray, ndarray)
|
|
94
|
+
Two tuple consisting of array of the minimum and maximum indices.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
slices : list
|
|
99
|
+
List of slice objects which return points between limits
|
|
100
|
+
|
|
101
|
+
See Also
|
|
102
|
+
--------
|
|
103
|
+
find_limits : Find the minimum and maximum limits from a list of points.
|
|
104
|
+
slice2limits : Find a minimum and maximum limits for a list of slices.
|
|
105
|
+
|
|
106
|
+
"""
|
|
107
|
+
mins, maxs = limits
|
|
108
|
+
return tuple([slice(i, j + 1) for i, j in zip(mins, maxs)])
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def slice2limits(slices):
|
|
112
|
+
"""
|
|
113
|
+
Create a tuple of minimum, maximum limits from a set of slices.
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
slices : list
|
|
118
|
+
List of slice objects which return points between limits
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
limits: tuple, (ndarray, ndarray)
|
|
123
|
+
Two tuple consisting of array of the minimum and maximum indices.
|
|
124
|
+
|
|
125
|
+
See Also
|
|
126
|
+
--------
|
|
127
|
+
limits2slice : Find a list of slices given minimum and maximum limits.
|
|
128
|
+
"""
|
|
129
|
+
mins = [s.start for s in slices]
|
|
130
|
+
maxs = [s.stop - 1 for s in slices]
|
|
131
|
+
return mins, maxs
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def squish(r, axis):
|
|
135
|
+
"""
|
|
136
|
+
Squish array along an axis.
|
|
137
|
+
|
|
138
|
+
Determine the sum along all but one axis for an array.
|
|
139
|
+
|
|
140
|
+
Parameters
|
|
141
|
+
----------
|
|
142
|
+
r : ndarray
|
|
143
|
+
Array to squish.
|
|
144
|
+
axis : int
|
|
145
|
+
Axis of r to squish along.
|
|
146
|
+
|
|
147
|
+
Returns
|
|
148
|
+
-------
|
|
149
|
+
s : 1D ndarray
|
|
150
|
+
Array r squished into a single dimension.
|
|
151
|
+
|
|
152
|
+
"""
|
|
153
|
+
# put axis to be squished as the last axis
|
|
154
|
+
N = int(r.ndim)
|
|
155
|
+
r = r.swapaxes(axis, N - 1)
|
|
156
|
+
|
|
157
|
+
# sum along leading axis N-1 times
|
|
158
|
+
for i in range(N - 1):
|
|
159
|
+
r = r.sum(0)
|
|
160
|
+
return r
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# Windowing classes
|
|
164
|
+
class ndwindow:
|
|
165
|
+
"""
|
|
166
|
+
An N-dimensional iterator to slice arrays into windows.
|
|
167
|
+
|
|
168
|
+
Given the shape of an array and a window size, an 'ndwindow' instance
|
|
169
|
+
iterators over tuples of slices which slice an the array into wsize
|
|
170
|
+
sub-arrays. At each iteration, the index of the center of the sub-array
|
|
171
|
+
is incremented by one along the last dimension. Array borders are ignored
|
|
172
|
+
so the resulting sub-array can be smaller than wsize. If wsize contains
|
|
173
|
+
even values the window is off center containing an additional point with
|
|
174
|
+
lower index.
|
|
175
|
+
|
|
176
|
+
Parameters
|
|
177
|
+
----------
|
|
178
|
+
size : tuple of ints
|
|
179
|
+
Size of array to generate tuples of slices from.
|
|
180
|
+
wsize : tuple of ints
|
|
181
|
+
Window/sub-array size. Size of the area to select from array. This is
|
|
182
|
+
the maximum size of the window.
|
|
183
|
+
|
|
184
|
+
Examples
|
|
185
|
+
--------
|
|
186
|
+
|
|
187
|
+
>>> a = np.arange(12).reshape(3,4)
|
|
188
|
+
>>> for s in ndwindow(a.shape,(3,3)):
|
|
189
|
+
... print(a[s])
|
|
190
|
+
[[0 1]
|
|
191
|
+
[4 5]]
|
|
192
|
+
[[0 1 2]
|
|
193
|
+
[4 5 6]]
|
|
194
|
+
[[1 2 3]
|
|
195
|
+
[5 6 7]]
|
|
196
|
+
[[2 3]
|
|
197
|
+
[6 7]]
|
|
198
|
+
[[0 1]
|
|
199
|
+
[4 5]
|
|
200
|
+
[8 9]]
|
|
201
|
+
[[ 0 1 2]
|
|
202
|
+
[ 4 5 6]
|
|
203
|
+
[ 8 9 10]]
|
|
204
|
+
[[ 1 2 3]
|
|
205
|
+
[ 5 6 7]
|
|
206
|
+
[ 9 10 11]]
|
|
207
|
+
[[ 2 3]
|
|
208
|
+
[ 6 7]
|
|
209
|
+
[10 11]]
|
|
210
|
+
[[4 5]
|
|
211
|
+
[8 9]]
|
|
212
|
+
[[ 4 5 6]
|
|
213
|
+
[ 8 9 10]]
|
|
214
|
+
[[ 5 6 7]
|
|
215
|
+
[ 9 10 11]]
|
|
216
|
+
[[ 6 7]
|
|
217
|
+
[10 11]]
|
|
218
|
+
|
|
219
|
+
See Also
|
|
220
|
+
--------
|
|
221
|
+
ndwindow_index : Iterator of a ndwindow and index of the window center
|
|
222
|
+
ndwindow_inside : Iterator over equal sized windows in the array.
|
|
223
|
+
|
|
224
|
+
"""
|
|
225
|
+
def __init__(self, shape, wsize):
|
|
226
|
+
""" Set up the ndwindow object """
|
|
227
|
+
if len(shape) != len(wsize):
|
|
228
|
+
raise ValueError("shape and wsize do match match")
|
|
229
|
+
self.ndindex = np.ndindex(shape)
|
|
230
|
+
wsize = np.array(wsize)
|
|
231
|
+
self.sub = np.ceil((wsize - 1.) / 2.)
|
|
232
|
+
self.add = wsize - 1. - self.sub
|
|
233
|
+
|
|
234
|
+
def __next__(self):
|
|
235
|
+
""" next iterator. """
|
|
236
|
+
return self.next()
|
|
237
|
+
|
|
238
|
+
def next(self):
|
|
239
|
+
""" x.next() -> the next value, or raise StopIteration """
|
|
240
|
+
center = self.ndindex.next()
|
|
241
|
+
start = [max(0, i - j) for i, j in zip(center, self.sub)]
|
|
242
|
+
stop = [i + j + 1 for i, j in zip(center, self.add)]
|
|
243
|
+
return tuple([slice(x, y) for x, y in zip(start, stop)])
|
|
244
|
+
|
|
245
|
+
def __iter__(self):
|
|
246
|
+
""" x.__iter__() <==> iter(x) """
|
|
247
|
+
return self
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class ndwindow_index:
|
|
251
|
+
"""
|
|
252
|
+
An N-dimensional iterator object which returns the index of the window
|
|
253
|
+
center and a :py:class:`ndwindow` slice array. See :py:class:`ndwindow`
|
|
254
|
+
for additional documentation.
|
|
255
|
+
|
|
256
|
+
This class is equivalent to:
|
|
257
|
+
|
|
258
|
+
for slices, index in zip(np.ndindex(shape), ndwindow(shape,wshape)):
|
|
259
|
+
return (index, slice)
|
|
260
|
+
|
|
261
|
+
See Also
|
|
262
|
+
--------
|
|
263
|
+
ndwindow: Iterator over only the window slices.
|
|
264
|
+
ndwindow_inside : Iterator over equal sized windows in the array.
|
|
265
|
+
|
|
266
|
+
"""
|
|
267
|
+
def __init__(self, shape, wsize):
|
|
268
|
+
""" Set up the object """
|
|
269
|
+
if len(shape) != len(wsize):
|
|
270
|
+
raise ValueError("shape and wsize do match match")
|
|
271
|
+
self.ndindex = np.ndindex(shape)
|
|
272
|
+
wsize = np.array(wsize)
|
|
273
|
+
self.sub = np.ceil((wsize - 1.) / 2.)
|
|
274
|
+
self.add = wsize - 1. - self.sub
|
|
275
|
+
|
|
276
|
+
def __next__(self):
|
|
277
|
+
""" next iterator. """
|
|
278
|
+
return self.next()
|
|
279
|
+
|
|
280
|
+
def next(self):
|
|
281
|
+
""" x.next() -> the next value, or raise StopIteration """
|
|
282
|
+
center = self.ndindex.next()
|
|
283
|
+
start = [max(0, i - j) for i, j in zip(center, self.sub)]
|
|
284
|
+
stop = [i + j + 1 for i, j in zip(center, self.add)]
|
|
285
|
+
return center, tuple([slice(x, y) for x, y in zip(start, stop)])
|
|
286
|
+
|
|
287
|
+
def __iter__(self):
|
|
288
|
+
""" x.__iter__() <==> iter(x) """
|
|
289
|
+
return self
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class ndwindow_inside:
|
|
293
|
+
"""
|
|
294
|
+
An N-dimensional iterator to slice arrays into uniform size windows.
|
|
295
|
+
|
|
296
|
+
Given the shape of an array and a window size, an 'ndwindow_inside'
|
|
297
|
+
instance iterators over tuples of slices which slice an the array into
|
|
298
|
+
uniform size wsize windows/sub-arrays. At each iteration, the index of
|
|
299
|
+
the top left of the sub-array is incremented by one along the last
|
|
300
|
+
dimension until the resulting windows would extend past the array border.
|
|
301
|
+
All sub-arrays are equal sized (wsize).
|
|
302
|
+
|
|
303
|
+
Parameters
|
|
304
|
+
----------
|
|
305
|
+
size : tuple of ints
|
|
306
|
+
Size of array to generate tuples of slices from.
|
|
307
|
+
wsize : tuple of ints
|
|
308
|
+
Size of the area to select from array (widow size).
|
|
309
|
+
|
|
310
|
+
Examples
|
|
311
|
+
--------
|
|
312
|
+
|
|
313
|
+
>>> a = np.arange(9).reshape(3,3)
|
|
314
|
+
>>> for s in ndwindow_inside(a.shape,(2,2)):
|
|
315
|
+
... print(a[s])
|
|
316
|
+
[[0 1]
|
|
317
|
+
[3 4]]
|
|
318
|
+
[[1 2]
|
|
319
|
+
[4 5]]
|
|
320
|
+
[[3 4]
|
|
321
|
+
[6 7]]
|
|
322
|
+
[[4 5]
|
|
323
|
+
[7 8]]
|
|
324
|
+
|
|
325
|
+
See Also
|
|
326
|
+
--------
|
|
327
|
+
ndwindow : Iterator over non-uniform windows.
|
|
328
|
+
ndwindow_inside_index : Iterator of a ndwindow_inside and the index of the
|
|
329
|
+
window's top left point.
|
|
330
|
+
|
|
331
|
+
"""
|
|
332
|
+
def __init__(self, shape, wsize):
|
|
333
|
+
""" Set up the object """
|
|
334
|
+
if len(shape) != len(wsize):
|
|
335
|
+
raise ValueError("shape and wsize do match match")
|
|
336
|
+
self.ndindex = np.ndindex(
|
|
337
|
+
tuple(np.array(shape) - np.array(wsize) + 1))
|
|
338
|
+
self.wsize = wsize
|
|
339
|
+
|
|
340
|
+
def __next__(self):
|
|
341
|
+
""" next iterator. """
|
|
342
|
+
return self.next()
|
|
343
|
+
|
|
344
|
+
def next(self):
|
|
345
|
+
""" x.next() -> the next value, or raise StopIteration """
|
|
346
|
+
start = self.ndindex.next()
|
|
347
|
+
stop = np.array(start) + np.array(self.wsize)
|
|
348
|
+
return tuple([slice(x, y) for x, y in zip(start, stop)])
|
|
349
|
+
|
|
350
|
+
def __iter__(self):
|
|
351
|
+
""" x.__iter__() <==> iter(x) """
|
|
352
|
+
return self
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
class ndwindow_inside_index:
|
|
356
|
+
"""
|
|
357
|
+
An N-dimensional iterator object which returns the index of the window
|
|
358
|
+
top-left and a :py:class:`ndwindow_inside` slice array.
|
|
359
|
+
|
|
360
|
+
Similar to :py:class:`ndwindow_index` but reports top left index of
|
|
361
|
+
window.
|
|
362
|
+
|
|
363
|
+
See :py:class:`ndwindow_inside` and :py:class`ndwindow_index` for addition
|
|
364
|
+
documentation.
|
|
365
|
+
|
|
366
|
+
"""
|
|
367
|
+
def __init__(self, shape, wsize):
|
|
368
|
+
" Set up the object """
|
|
369
|
+
if len(shape) != len(wsize):
|
|
370
|
+
raise ValueError("shape and wsize do match match")
|
|
371
|
+
self.ndindex = np.ndindex(
|
|
372
|
+
tuple(np.array(shape) - np.array(wsize) + 1))
|
|
373
|
+
self.wsize = wsize
|
|
374
|
+
|
|
375
|
+
def __next__(self):
|
|
376
|
+
""" next iterator. """
|
|
377
|
+
return self.next()
|
|
378
|
+
|
|
379
|
+
def next(self):
|
|
380
|
+
""" x.next() -> the next value, or raiseStopIteration """
|
|
381
|
+
start = self.ndindex.next()
|
|
382
|
+
stop = np.array(start) + np.array(self.wsize)
|
|
383
|
+
return (start, tuple([slice(x, y) for x, y in zip(start, stop)]))
|
|
384
|
+
|
|
385
|
+
def __iter__(self):
|
|
386
|
+
""" x.__iter__() <==> iter(x) """
|
|
387
|
+
return self
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Helper functions for lineshape fitting.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# bound functions
|
|
7
|
+
def delta(v, d):
|
|
8
|
+
"""
|
|
9
|
+
Limits of v +/- d for array v and d.
|
|
10
|
+
"""
|
|
11
|
+
return zip(v - d, v + d)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def limit(vmin, vmax, npeaks):
|
|
15
|
+
"""
|
|
16
|
+
Fixed limits, vmin to vmax for all peaks.
|
|
17
|
+
"""
|
|
18
|
+
return [(vmin, vmax)] * npeaks
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def scale_params(rec, prefix, first, last):
|
|
22
|
+
"""
|
|
23
|
+
scale lineshape parameters in rec with name prefixX with X from from
|
|
24
|
+
first to last (inclusive)
|
|
25
|
+
"""
|
|
26
|
+
return [rec[prefix + str(z)] for z in range(first, last + 1)]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def no_limits(nparams, npeaks):
|
|
30
|
+
"""
|
|
31
|
+
No limits on nparameters for npeaks.
|
|
32
|
+
"""
|
|
33
|
+
return [[(None, None)] * npeaks] * nparams
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def no_limits_amp(npeaks):
|
|
37
|
+
"""
|
|
38
|
+
No amplitude limits for npeaks
|
|
39
|
+
"""
|
|
40
|
+
return [(None, None)] * npeaks
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# misc
|
|
44
|
+
def super_zip(l):
|
|
45
|
+
"""
|
|
46
|
+
Zip a list after zipping each element.
|
|
47
|
+
|
|
48
|
+
Useful for lineshape parameter and bounds.
|
|
49
|
+
"""
|
|
50
|
+
return zip(*[zip(*i) for i in l])
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def scale_columns(prefix, first, last):
|
|
54
|
+
"""
|
|
55
|
+
Create a list of scale parameter column names with name prefixX with X
|
|
56
|
+
from first to last (inclusive)
|
|
57
|
+
"""
|
|
58
|
+
return [prefix + str(i) for i in range(first, last + 1)]
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def integrate(data, unit_conv, limits, unit='ppm', noise_limits=None,
|
|
5
|
+
norm_to_range=None, calibrate=1.0):
|
|
6
|
+
r"""
|
|
7
|
+
Integrate one 1D data array within limits given in units. Data points must
|
|
8
|
+
be equally spaced.
|
|
9
|
+
|
|
10
|
+
Functional form of integration is:
|
|
11
|
+
|
|
12
|
+
.. math::
|
|
13
|
+
value = \sum_a^b s(x_{i}) dx
|
|
14
|
+
|
|
15
|
+
Where:
|
|
16
|
+
s is the signal, a and b are the limits of integration and dx is the width
|
|
17
|
+
of each bin.
|
|
18
|
+
|
|
19
|
+
The integration error due to baseline noise is calculated as:
|
|
20
|
+
|
|
21
|
+
.. math::
|
|
22
|
+
error = \sigma_{vol} = \sigma \sqrt{n}
|
|
23
|
+
|
|
24
|
+
if the noise_limits are set.
|
|
25
|
+
|
|
26
|
+
Where:
|
|
27
|
+
|
|
28
|
+
.. math::
|
|
29
|
+
n = \frac{|b-a|}{dx}+1
|
|
30
|
+
|
|
31
|
+
sigma is the standard deviation of the baseline noise. n is the number
|
|
32
|
+
of bins in the integration range.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
data: array like
|
|
37
|
+
1d array of intensity
|
|
38
|
+
unit_conv: `fileiobase.unit_conversion` object
|
|
39
|
+
unit_conversion object associated with data
|
|
40
|
+
limits: array like
|
|
41
|
+
With shape (2,) or (P, 2). Array with lower and upper integration
|
|
42
|
+
limit. Or array with P rows of lower and upper integration limits.
|
|
43
|
+
noise_limits: Optional[array like]
|
|
44
|
+
With shape(2, ). Array with lower and upper limits to section of data
|
|
45
|
+
with only noise. A larger range will likely yield a more accurate
|
|
46
|
+
estimate. It is unwise to use the very end of the spectrum for the
|
|
47
|
+
noise range.
|
|
48
|
+
norm_to_range: Optional[int]
|
|
49
|
+
If given, all values are normalized to the value determined within the
|
|
50
|
+
range given by limits[norm_to_range, :]
|
|
51
|
+
calibrate: Optional[float]
|
|
52
|
+
If norm_to_range is given, the values are re-normalized so that the
|
|
53
|
+
integral within limits[norm_to_range, :] equals some number.
|
|
54
|
+
|
|
55
|
+
Returns
|
|
56
|
+
-------
|
|
57
|
+
array
|
|
58
|
+
[value, ...] integration values
|
|
59
|
+
|
|
60
|
+
if noise_limits is given:
|
|
61
|
+
|
|
62
|
+
array
|
|
63
|
+
[[value, error], ...] where error a one sigma estimate of the error
|
|
64
|
+
only from the spectrum noise
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
# convert form limits in units to lower and upper index
|
|
68
|
+
limits = np.array(limits)
|
|
69
|
+
if limits.size == 2:
|
|
70
|
+
limits = np.expand_dims(limits, axis=0)
|
|
71
|
+
inds = [(unit_conv(x0, unit), unit_conv(x1, unit)) for (x0, x1) in limits]
|
|
72
|
+
inds = np.array([sorted(ind) for ind in inds])
|
|
73
|
+
|
|
74
|
+
# sum part of the integral
|
|
75
|
+
sum_slice = np.array([np.sum(data[slice(*ind)]) for ind in inds])
|
|
76
|
+
|
|
77
|
+
# dx part of the integral
|
|
78
|
+
scale = unit_conv.ppm_scale()
|
|
79
|
+
dx = abs(scale[1]-scale[0])
|
|
80
|
+
|
|
81
|
+
# put together the integral
|
|
82
|
+
values = sum_slice * dx
|
|
83
|
+
|
|
84
|
+
if noise_limits is not None:
|
|
85
|
+
|
|
86
|
+
# determine the standard deviation of the noise
|
|
87
|
+
noise_inds = (unit_conv(noise_limits[0], unit),
|
|
88
|
+
unit_conv(noise_limits[1], unit))
|
|
89
|
+
noise_inds = sorted(noise_inds)
|
|
90
|
+
|
|
91
|
+
# the error (from noise) is std * dx * limits range
|
|
92
|
+
std = np.std(data[slice(*noise_inds)])
|
|
93
|
+
errors = std * np.sqrt(inds[:, 1] - inds[:, 0])
|
|
94
|
+
|
|
95
|
+
if norm_to_range is not None:
|
|
96
|
+
# You must normalize the error before you normalize the value!
|
|
97
|
+
errors = (errors / values[norm_to_range]) * calibrate
|
|
98
|
+
values = (values / values[norm_to_range]) * calibrate
|
|
99
|
+
return np.vstack((values, errors)).T
|
|
100
|
+
|
|
101
|
+
else:
|
|
102
|
+
|
|
103
|
+
if norm_to_range is not None:
|
|
104
|
+
values = (values / values[norm_to_range]) * calibrate
|
|
105
|
+
return values
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def ndintegrate(data, unit_conv, limits, unit='ppm', noise_limits=None):
|
|
109
|
+
r"""
|
|
110
|
+
Integrate one nD data array within limits given in units. Data points must
|
|
111
|
+
be equally spaced. Can only integrate one region per function call.
|
|
112
|
+
|
|
113
|
+
The integration error due to baseline noise is calculated as:
|
|
114
|
+
|
|
115
|
+
.. math::
|
|
116
|
+
error = \sigma_{vol} = \sigma \sqrt{\prod_i^{d} n_{i}},
|
|
117
|
+
|
|
118
|
+
if the noise_limits are set.
|
|
119
|
+
|
|
120
|
+
Where:
|
|
121
|
+
sigma is the standard deviation of the baseline noise. n is the number
|
|
122
|
+
of bins in the integration range for each d dimensions.
|
|
123
|
+
|
|
124
|
+
See integrate for more information.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
data: array like
|
|
129
|
+
1d array of intensity
|
|
130
|
+
unit_convs: [`fileiobase.unit_conversion`, ] list
|
|
131
|
+
list of unit_conversion object associated with each dim of data.
|
|
132
|
+
limits: array like
|
|
133
|
+
With shape (2,) or (d, 2). 1D Array with lower and upper integration
|
|
134
|
+
limits for 1D . Or array with d rows of lower and upper integration
|
|
135
|
+
limits for each dimension.
|
|
136
|
+
noise_limits: Optional[array like]
|
|
137
|
+
With shape(2, ). Array with lower and upper limits to section of data
|
|
138
|
+
with only noise. A larger range will likely yield a more accurate
|
|
139
|
+
estimate. It is unwise to use the very end of the spectrum for the
|
|
140
|
+
noise range.
|
|
141
|
+
|
|
142
|
+
Returns
|
|
143
|
+
-------
|
|
144
|
+
array
|
|
145
|
+
[value, ...] integration values
|
|
146
|
+
|
|
147
|
+
if noise_limits is given:
|
|
148
|
+
|
|
149
|
+
array
|
|
150
|
+
[[value, error], ...] where error a one sigma estimate of the error
|
|
151
|
+
only from the spectrum noise
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
# determine the dimensionality of the data.
|
|
155
|
+
d = np.ndim(data)
|
|
156
|
+
|
|
157
|
+
try:
|
|
158
|
+
iter(unit_conv)
|
|
159
|
+
except TypeError:
|
|
160
|
+
unit_conv = [unit_conv, ]
|
|
161
|
+
|
|
162
|
+
if d != len(unit_conv):
|
|
163
|
+
mesg = 'A unit_conversion object is needed for each dimension.'
|
|
164
|
+
raise ValueError(mesg)
|
|
165
|
+
|
|
166
|
+
limits = np.array(limits)
|
|
167
|
+
if limits.ndim == 1:
|
|
168
|
+
limits = np.expand_dims(limits, axis=0)
|
|
169
|
+
|
|
170
|
+
if limits.shape[0] != d and limits.shape[1] != 2:
|
|
171
|
+
mesg = 'A lower and upper limit is needed for each dimension.'
|
|
172
|
+
raise ValueError(mesg)
|
|
173
|
+
|
|
174
|
+
inds = [(uc(x[0], unit), uc(x[1], unit))
|
|
175
|
+
for (uc, x) in zip(unit_conv, limits)]
|
|
176
|
+
inds = [sorted(x) for x in inds]
|
|
177
|
+
|
|
178
|
+
# the integrate_nd needs to be scaled by the bin width in ppm
|
|
179
|
+
ppm_scales = [x.ppm_scale() for x in unit_conv]
|
|
180
|
+
dx = np.prod(np.array([abs(x[1]-x[0]) for x in ppm_scales]))
|
|
181
|
+
|
|
182
|
+
slice_sum = (data[tuple([slice(x[0], x[1]) for x in np.flipud(inds)])]).sum()
|
|
183
|
+
|
|
184
|
+
value = slice_sum * dx
|
|
185
|
+
|
|
186
|
+
if noise_limits is None:
|
|
187
|
+
return value
|
|
188
|
+
|
|
189
|
+
else:
|
|
190
|
+
noise_limits = np.array(noise_limits)
|
|
191
|
+
if noise_limits.size == 2:
|
|
192
|
+
noise_limits = np.expand_dims(noise_limits, axis=0)
|
|
193
|
+
|
|
194
|
+
if noise_limits.shape[0] != d and noise_limits.shape[1] != 2:
|
|
195
|
+
mesg = 'If given, a noise limit is needed for each dimension.'
|
|
196
|
+
raise ValueError(mesg)
|
|
197
|
+
|
|
198
|
+
noise_inds = [(uc(x[0], unit), uc(x[1], unit))
|
|
199
|
+
for (uc, x) in zip(unit_conv, noise_limits)]
|
|
200
|
+
noise_inds = [sorted(x) for x in noise_inds]
|
|
201
|
+
|
|
202
|
+
# see docstring of integrate
|
|
203
|
+
nm = np.prod(np.array([abs(x[1]-x[0]) for x in noise_inds]))
|
|
204
|
+
std = np.std(data[[slice(x[0], x[1])for x in np.flipud(noise_inds)]])
|
|
205
|
+
|
|
206
|
+
error = std * np.sqrt(nm)
|
|
207
|
+
return np.hstack((value, error))
|