Skip to content

Commit a7f8592

Browse files
committed
Features and bug-fixes
- Reimplemented csv-writing of each data block (separate at the moment) - Fixed injection selection/read-out - y-axis2 is Conductivity now by default
1 parent b6c0689 commit a7f8592

File tree

2 files changed

+147
-72
lines changed

2 files changed

+147
-72
lines changed

examplescripts/pycorn-bin.py

+118-36
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,74 @@
1-
import argparse
2-
# from pathlib import Path
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
33

4+
import argparse
45
from mpl_toolkits.axes_grid1 import host_subplot
6+
from matplotlib.ticker import AutoMinorLocator
57
import mpl_toolkits.axisartist as AA
68
import matplotlib.pyplot as plt
7-
# ^^^ = from matplotlib.pyplot import axvline, savefig, subplots, annotate
8-
99
from pycorn import pc_res3
1010

11-
parser = argparse.ArgumentParser()
11+
pcscript_version = 0.13
1212

13+
parser = argparse.ArgumentParser(
14+
description = "Extract data from UNICORN .res files to .csv/.txt and plot them (matplotlib required)",
15+
epilog = "Make it so!")
16+
parser.add_argument("-c", "--check",
17+
help = "Perform simple check if file is supported",
18+
action = "store_true")
19+
parser.add_argument("-n", "--info",
20+
help = "Display entries in header",
21+
action = "store_true")
22+
parser.add_argument("-i", "--inject", type = int, default = None,
23+
help = "Set injection number # as zero retention, use -t to find injection points",
24+
metavar="#")
25+
parser.add_argument("-r", "--reduce", type = int, default = 1,
26+
help = "Write/Plot only every n sample",
27+
metavar="#")
28+
parser.add_argument("-t", "--points",
29+
help = "Display injection points",
30+
action = "store_true")
31+
32+
group0 = parser.add_argument_group('Extracting', 'Options for writing csv/txt files')
33+
group0.add_argument("-e", "--extract",
34+
help = "Write csv file for supported data blocks",
35+
action = "store_true")
36+
37+
group1 = parser.add_argument_group('Plotting', 'Options for plotting')
38+
group1.add_argument("-p", "--plot",
39+
help = 'Plot curves',
40+
action = "store_true")
41+
group1.add_argument("--no_fractions",
42+
help="Disable plotting of fractions",
43+
action = "store_false")
44+
group1.add_argument("--xmin", type = float, default=None,
45+
help="Lower bound on the x-axis",
46+
metavar="#")
47+
group1.add_argument("--xmax", type = float, default=None,
48+
help="Upper bound on the x-axis",
49+
metavar="#")
50+
group1.add_argument("--par1", type = str, default='Cond',
51+
help="Data for 2nd y-axis (Default=Cond)")
52+
group1.add_argument("--par2", type = str, default=None,
53+
help="Data for 3rd y-axis (Default=None)")
54+
group1.add_argument('-f', '--format', type = str,
55+
choices=['svg','svgz','tif','tiff','jpg','jpeg',
56+
'png','ps','eps','raw','rgba','pdf','pgf'],
57+
default = 'pdf',
58+
help = "File format of plot files (default: pdf)")
59+
group1.add_argument('-d', '--dpi', default=300, type=int,
60+
help="DPI (dots per inch) for raster images (png, jpg, etc.). Default is 300.")
61+
parser.add_argument("-u", "--user",
62+
help = "Show stored user name",
63+
action = "store_true")
64+
parser.add_argument('--version', action='version', version=str(pcscript_version))
1365
parser.add_argument("inp_res",
1466
help="Input .res file(s)",
1567
nargs='+',
1668
metavar="<file>.res")
17-
parser.add_argument("-e", "--ext", default='.pdf',
18-
help="Image type to use, e.g. 'jpg', 'png', 'eps', or 'pdf' (default: pdf)")
19-
parser.add_argument("--xmin", default=None, type=float,
20-
help="Lower bound on the x-axis")
21-
parser.add_argument("--xmax", default=None, type=float,
22-
help="Upper bound on the x-axis")
23-
parser.add_argument("--dpi", default=None, type=int,
24-
help="DPI (dots per inch) for raster images (png, jpg, etc.)")
25-
parser.add_argument("--par1", default=None, type=str,
26-
help="First parasite")
27-
parser.add_argument("--par2", default=None, type=str,
28-
help="Second parasite")
29-
30-
3169

3270
args = parser.parse_args()
3371

34-
3572
def mapper(min_val, max_val, perc):
3673
'''
3774
calculate relative position in delta min/max
@@ -177,26 +214,56 @@ def plotterX(inp,fname):
177214
print("Plotting: " + par2_data['data_name'])
178215
p2, = par2.plot(x_dat_p2, y_dat_p2, label=par2_data['data_name'], color=stl['color'],
179216
ls=stl['ls'], lw=stl['lw'], alpha=stl['alpha'])
180-
try:
181-
frac_data = inp['Fractions']['data']
182-
frac_x, frac_y = xy_data(frac_data)
183-
frac_delta = [abs(a - b) for a, b in zip(frac_x, frac_x[1:])]
184-
frac_delta.append(frac_delta[-1])
185-
frac_y_pos = mapper(host.get_ylim()[0], host.get_ylim()[1], 0.015)
186-
for i in frac_data:
187-
host.axvline(x=i[0], ymin=0.065, ymax=0.0, color='r', linewidth=0.85)
188-
host.annotate(str(i[1]), xy=(i[0] + frac_delta[frac_data.index(i)] * 0.55, frac_y_pos),
217+
if args.no_fractions:
218+
try:
219+
frac_data = inp['Fractions']['data']
220+
frac_x, frac_y = xy_data(frac_data)
221+
frac_delta = [abs(a - b) for a, b in zip(frac_x, frac_x[1:])]
222+
frac_delta.append(frac_delta[-1])
223+
frac_y_pos = mapper(host.get_ylim()[0], host.get_ylim()[1], 0.015)
224+
for i in frac_data:
225+
host.axvline(x=i[0], ymin=0.065, ymax=0.0, color='r', linewidth=0.85)
226+
host.annotate(str(i[1]), xy=(i[0] + frac_delta[frac_data.index(i)] * 0.55, frac_y_pos),
189227
horizontalalignment='center', verticalalignment='bottom', size=8, rotation=90)
190-
except:
191-
KeyError
228+
except:
229+
KeyError
192230
host.set_xlim(plot_x_min, plot_x_max)
193-
host.legend(fontsize=8, fancybox=True, labelspacing=0.4)
231+
host.legend(fontsize=8, fancybox=True, labelspacing=0.4, loc='upper right')
232+
host.xaxis.set_minor_locator(AutoMinorLocator())
233+
host.yaxis.set_minor_locator(AutoMinorLocator())
194234
plt.title(fname, loc='left')
195235
internal_run_name = str(inp['Logbook']['run_name'])
196-
plot_file = fname[:-4] + "_" + internal_run_name + "_plot" + args.ext
236+
plot_file = fname[:-4] + "_" + internal_run_name + "_plot." + args.format
197237
plt.savefig(plot_file, bbox_inches='tight', dpi=args.dpi)
198238
print("Plot saved to: " + plot_file)
199-
#4e62ff
239+
240+
def data_writer1(fname, inp):
241+
'''
242+
writes sensor/run-data to csv-files
243+
'''
244+
run_name = inp['Logbook']['run_name']
245+
for i in inp.keys():
246+
print("Extracting: " + inp[i]['data_name'])
247+
outfile_base = fname[:-4] + "_" + run_name + "_" + inp[i]['data_name']
248+
type = inp[i]['data_type']
249+
if type == 'meta':
250+
data = inp[i]['data']
251+
data_to_write = data.encode('utf-8')
252+
ext = '.txt'
253+
sep = '\t'
254+
with open(outfile_base + ext, 'wb') as fout:
255+
fout.write(data_to_write)
256+
else:
257+
x_dat,y_dat = xy_data(inp[i]['data'])
258+
ext = '.csv'
259+
sep = ','
260+
with open(outfile_base + ext, 'wb') as fout:
261+
for x,y in zip(x_dat,y_dat):
262+
dp = str(x) + sep + str(y) + str('\r\n')
263+
data_to_write = dp.encode('utf-8')
264+
fout.write(data_to_write)
265+
266+
200267
styles = {'UV':{'color': '#1919FF', 'lw': 1.6, 'ls': "-", 'alpha':1.0},
201268
'UV1_':{'color': '#1919FF', 'lw': 1.6, 'ls': "-", 'alpha':1.0},
202269
'UV2_':{'color': '#e51616', 'lw': 1.4, 'ls': "-", 'alpha':1.0},
@@ -208,10 +275,25 @@ def plotterX(inp,fname):
208275
'Inje':{'color': '#d56d9d', 'lw': 1.0, 'ls': "-", 'alpha':0.75},
209276
'pH':{'color': '#0C7F7F', 'lw': 1.0, 'ls': "-", 'alpha':0.75},}
210277

278+
211279
def main2():
212280
for fname in args.inp_res:
213-
fdata = pc_res3(fname)
281+
if args.inject == None:
282+
args.inject = -1
283+
fdata = pc_res3(fname, reduce = args.reduce, inj_sel=args.inject)
214284
fdata.load()
215-
plotterX(fdata, fname)
285+
if args.extract:
286+
data_writer1(fname, fdata)
287+
if args.check:
288+
fdata.input_check(show=True)
289+
if args.info:
290+
fdata.showheader()
291+
if args.points:
292+
fdata.inject_det(show=True)
293+
if args.user:
294+
user = fdata.get_user()
295+
print("User: " + user)
296+
if args.plot:
297+
plotterX(fdata, fname)
216298

217299
main2()

pycorn/pycorn.py

+29-36
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import codecs
1414
import os
1515

16-
1716
class pc_res3(OrderedDict):
1817
"""A class for holding the PyCORN/RESv3 data.
1918
A subclass of `dict`, with the form `data_name`: `data`.
@@ -33,12 +32,13 @@ class pc_res3(OrderedDict):
3332
Inject_id2 = b'\x00\x00\x01\x00\x04\x00\x47\x04'
3433
LogBook_id = b'\x00\x00\x01\x00\x02\x00\x01\x13' # capital B!
3534

36-
def __init__(self, file_name, reduce=1, default_inject=1):
35+
def __init__(self, file_name, reduce=1, inj_sel=-1):
3736
OrderedDict.__init__(self)
3837
self.file_name = file_name
3938
self.reduce = reduce
40-
self.default_inject = default_inject
41-
self.inj_sel = 0.0 # injection point is by default 0.0 ml
39+
self.injection_points = None
40+
self.inj_sel = inj_sel
41+
self.inject_vol = None
4242
self.header_read = False
4343

4444
with open(self.file_name, 'rb') as f:
@@ -115,7 +115,6 @@ def showheader(self, full=True):
115115
'''
116116
Prints content of header
117117
'''
118-
self.readheader()
119118
print((" ---- \n Header of {0}: \n").format(self.file_name))
120119
if full:
121120
print(" MAGIC_ID, ENTRY_NAME, BLOCK_SIZE, OFFSET_TO_NEXT, ADRESSE, OFFSET_TO_DATA")
@@ -163,19 +162,21 @@ def dataextractor(self, dat, show=False):
163162
dat.update(data=values, unit=unit, data_type= 'curve')
164163
return dat
165164

166-
def meta1_read(self, dat, show=False):
165+
def meta1_read(self, dat, show=False, do_it_for_inj_det=False):
167166
'''
168167
Extracts meta-data/type1, Logbook, fractions and Inject marks
169168
for a specific datum
170169
'''
171170
if show:
172171
print((" Reading: {0}").format(dat['data_name']))
173172
final_data = []
174-
173+
inj_vol_to_subtract = self.inject_vol
174+
if do_it_for_inj_det:
175+
inj_vol_to_subtract = 0.0
175176
for i in range(dat['d_start'], dat['d_end'], 180):
176177
dp = struct.unpack("dd158s", self.raw_data[i:i + 174])
177178
# acc_time = dp[0] # not used atm
178-
acc_volume = round(dp[1] - self.inj_sel, 4)
179+
acc_volume = round(dp[1] - inj_vol_to_subtract, 4)
179180
label = (codecs.decode(dp[2], 'iso8859-1')).rstrip('\x00')
180181
merged_data = acc_volume, label
181182
final_data.append(merged_data)
@@ -219,51 +220,43 @@ def sensor_read(self, dat, show=False):
219220
s_unit_dec = (codecs.decode(s_unit[0], 'iso8859-1')).rstrip('\x00')
220221
for i in range(dat['d_start'], dat['d_end'], 8):
221222
sread = struct.unpack("ii", fread[i:i + 8])
222-
data = round((sread[0] / 100.0) - self.inj_sel, 4), sread[1] / sensor_div
223+
data = round((sread[0] / 100.0) - self.inject_vol, 4), sread[1] / sensor_div
223224
final_data.append(data)
224225
return (final_data[0::self.reduce], s_unit_dec)
225226

226227
def inject_det(self, show=False):
227228
'''
228229
Finds injection points - required for adjusting retention volume
229230
'''
230-
injection_points = []
231-
self.readheader()
232-
inject_ids = [self.Inject_id, self.Inject_id2]
233-
for i in self.values():
234-
if i['magic_id'] in inject_ids:
235-
injection = self.meta1_read(i, show=show)[0][0]
236-
injection_points.append(injection)
237-
if injection != 0.0:
238-
injection_points.insert(0, 0.0)
239-
if injection_points == []:
240-
injection_points = [0.0]
241-
if show:
242-
print((" ---- \n Injection points: \n # \t ml \n 0 \t {0}").format(injection_points[0]))
243-
return (injection_points)
244-
else:
245-
if show:
246-
print(" ---- \n Injection points: \n # \t ml")
247-
for x, y in enumerate(injection_points):
248-
print((" {0} \t {1}").format(x, y))
249-
return (injection_points)
231+
if self.injection_points == None:
232+
self.injection_points = [0.0]
233+
inject_ids = [self.Inject_id, self.Inject_id2]
234+
for i in self.values():
235+
if i['magic_id'] in inject_ids:
236+
injection = self.meta1_read(i, show=show, do_it_for_inj_det=True)[0][0]
237+
if injection != 0.0:
238+
self.injection_points.append(injection)
239+
if show:
240+
print(" ---- \n Injection points: \n # \t ml")
241+
for x, y in enumerate(self.injection_points):
242+
print((" {0} \t {1}").format(x, y))
243+
250244

251245
def load(self, show=False):
252246
'''
253247
extract all data and store in list
254248
'''
255-
injection_points = self.inject_det(show=False)
249+
self.readheader()
250+
self.inject_det()
256251
try:
257-
self.inj_sel = injection_points[self.default_inject]
252+
self.inject_vol = self.injection_points[self.inj_sel]
258253
except IndexError:
259-
if show:
260-
print("\n ERROR - Injection point does not exist! Selected default.\n")
261-
self.inj_sel = injection_points[-1]
262-
self.readheader()
254+
print("\n WARNING - Injection point does not exist! Selected default.\n")
255+
self.inject_vol = self.injection_points[-1]
263256
for name, dat in list(self.items()):
264257
dat = self.dataextractor(dat, show=show)
265258
if dat is not None:
266259
self[name] = dat
267260
else:
268261
# TODO: Maybe we should keep this around?
269-
del self[name]
262+
del self[name]

0 commit comments

Comments
 (0)