-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathdata.py
285 lines (215 loc) · 8.45 KB
/
data.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
import spinmob as _s
import time as _t
import struct as _struct
import numpy as _n
import os as _os
import mcphysics as _mp
import glob as _glob
def load_chn(path=None, **kwargs):
"""
Loads a Maestro CHN file at the specified path. Will return a databox with all
the information.
Parameters
----------
path=None
If None, a dialog will pop up. Otherwise specify a valid path (string).
Optional keyword arguments, e.g., delimeter=',', are sent to spinmob.data.databox()
"""
if path==None: path = _s.dialogs.load(filters="*.Chn")
if path==None: return
# Create a databox
d = _s.data.databox(**kwargs)
# Open the file
fh = open(path,mode="rb")
# Read the buffer
buffer = fh.read()
# Unpack
[type, unitnumber, segment_number] = _struct.unpack("hhh",buffer[0:6])
ascii_seconds = buffer[6:8].decode()
[real_time_20ms, live_time_20ms] = _struct.unpack("ii",buffer[8:16])
start_date = buffer[16:24].decode()
start_time = buffer[24:28].decode()
[channel_offset, channel_count] = _struct.unpack("hh",buffer[28:32])
# Get the counts data
spectrum = _n.zeros(channel_count,dtype=int)
for i in range(channel_count): [spectrum[i]] = _struct.unpack("I",buffer[32+4*i:36+4*i])
# Get the byte offset of the data
offset = 36+4*(channel_count-1)
# Get the size of the "Sample description" string
info_size = int.from_bytes( buffer[offset+320:offset+321], "big" )
# Extract "Sample description" string
info = buffer[offset+321:offset+321+info_size].decode()
d['Channel'] = range(channel_count)
d['Counts'] = spectrum
# Get the date in a nice format
if "1" == start_date[7]: century = 20
else: century = 19
start_RFC2822 = "%s %s %02d%s %s:%s:%s" % (start_date[0:2], start_date[2:5], century, start_date[5:7], start_time[0:2], start_time[2:4], ascii_seconds)
s = _t.strptime(start_RFC2822,"%d %b %Y %H:%M:%S")
start = dict(
year = s.tm_year,
month = s.tm_mon,
day = s.tm_mday,
hour = s.tm_hour,
minute = s.tm_min,
second = s.tm_sec,
year_day = s.tm_yday)
# Header info
d.path=path
d.h(description = info,
start_time = start,
real_time = 0.02*real_time_20ms,
live_time = 0.02*live_time_20ms,
path = path,)
return d
def load_chns(paths=None, combine=False, **kwargs):
"""
Loads multiple chn files, returning a list of databoxes.
Parameters
----------
paths=None : list of paths
If None, a dialog will pop up, allowing you to select multiople files.
Otherwise, specify a valid *list* of paths, e.g. ['C:/test/path.chn', 'C:/test/path2.chn']
combine=False : bool
If True, the counts from all files will be summed into a single databox, rather
than returning a list of databoxes. The header of the returned databox
will be the header of the first file in the list.
Optional keyword arguments (e.g., delimiter=',') are sent to load_chn()
"""
if paths==None: paths=_s.dialogs.load_multiple(filters='*.Chn')
if paths==None: return
ds = []
for path in paths: ds.append(load_chn(path, **kwargs))
# If we're not combining
if not combine: return ds
# Otherwise, make a master databox.
dm = ds.pop(0)
for d in ds: dm[1] += d[1]
return dm
def plot_chns(xscript='d[0]', yscript='d[1]', eyscript='sqrt(d[1])', marker='+', linestyle='', xlabel='Channel', ylabel='Counts', paths=None, combine=False, **kwargs):
"""
Opens a bunch of chn files and plots the specified script for each. You can
get the same result by loading multiple chn files (returns a list of databoxes)
and sending the result to spinmob.plot.xy.databoxes().
Arguments
---------
xscript, yscript, eyscript
Scripts for creating the xdata, ydata, and error bars. These follow the
convention of spinmob.plot.xy.files(). Any valid python string evaluating to
an array of numbers will work. "d" refers to the databox being plotted, and
the system "knows" about all numpy functions. Specifying None for xscript
or yscript will generate integer arrays to match the other data sets.
marker, linestyle, xlabel, ylabel
Some common plot options.
combine=False : bool
If True, will sum the selected data into a single curve.
Additional optional keyword arguments are sent to spinmob.plot.xy.databoxes,
spinmob.plot.xy.data, and pylab.errorbar.
Returns
-------
List of databoxes.
"""
if paths==None: paths = _s.dialogs.load_multiple(filters='*.Chn')
if paths==None: return
# Load the files
ds = load_chns(paths, combine)
# If it's combined
if not type(ds) is list: ds = [ds]
# Get the title
title = _os.path.split(ds[0].path)[0]
_s.plot.xy.databoxes(ds, xscript, yscript, eyscript,
marker=marker, linestyle=linestyle,
xlabel=xlabel, ylabel=ylabel,
title=title, **kwargs)
return ds
def load_chns_directory(path=None, **kwargs):
"""
Calls load_chns() on all the *.Chn files in the specified directory. Will
alphabetize the list of files.
Parameters
----------
path=None : str
Optional directory. If None, a dialog will pop up to ask for a directory.
Additional keyword arguments are sent to load_chns()
Returns
-------
The result of load_chns()
"""
if path is None: path = _s.dialogs.select_directory('Select a directory containing Chn files!')
if path is None: return
paths = _glob.glob(_os.path.join(path,'*.Chn'))
paths.sort()
return load_chns(paths, **kwargs)
def plot_chns_directory(path=None, **kwargs):
"""
Calls plot_chns() on all the *.Chn files in the specified directory. Will
sort the files in the directory alphabetically.
Parameters
----------
path=None : str
Optional directory. If None, a dialog will pop up to ask for a directory.
Additional keyword arguments are sent to plot_chns()
Returns
-------
The result of plot_chns()
"""
if path is None: path = _s.dialogs.select_directory('Select a directory containing Chn files!')
if path is None: return
paths = _glob.glob(_os.path.join(path,'*.Chn'))
paths.sort()
return plot_chns(paths=paths, **kwargs)
def convert_chn_to_csv(chn_paths=None, output_dir=None):
"""
Opens the supplied Maestro Chn files and saves them as csv
Parameters
----------
chn_paths=None : list of strings
List of paths to Chn files. If None, this will pop up a dialog.
output_dir=None: string
Path to output directory. If None, this will pop up a dialog.
"""
ds = load_chns(chn_paths, delimiter=',')
if ds is None: return
if output_dir is None: output_dir = _s.dialogs.select_directory('Select an output directory.')
if output_dir is None: return
for d in ds:
# Get the file name
filename = _os.path.split(d.path)[-1]
# Replace the extension
s = filename.split('.')
s[-1] = 'csv'
filename = '.'.join(s)
# Save it
d.save_file(_os.path.join(output_dir, filename))
return ds
# Only import this if imageio is installed
def load_image(path=None):
"""
Loads an image, returning a 3D array: two indices for the pixel position
(x and y), and one index for the color, which can have either 3 values
(RGB) or 4 (RGBA), depending on the file format.
Parameters
----------
path=None
If None, a dialog will open up. Otherwise, specify a valid path (string).
"""
if not _mp._imageio: raise Exception('You need to install imageio for this function.')
if path == None: path = _s.dialogs.load()
if path == None: return
# Load the image into array "a".
return _mp._imageio.imread(path)
def load_images(paths=None):
"""
Loads multiple images, returning a list of 3D arrays, as per load_image.
Parameters
----------
paths=None
If None, a dialog will pop up. Otherwise, specify a *list* of valid
paths to images.
"""
if not _mp._imageio: raise Exception('You need to install imageio for this function.')
if paths == None: paths = _s.dialogs.load_multiple()
if paths == None: return
arrays = []
for path in paths: arrays.append(load_image(path))
return arrays