Skip to content

Commit f861bd1

Browse files
committed
add linestyle overload
1 parent 8692171 commit f861bd1

1 file changed

Lines changed: 75 additions & 76 deletions

File tree

apread/entries.py

Lines changed: 75 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ def read_chunk_from_file(file_path, start, end, typ, buf_loc) -> np.ndarray:
3535
f.seek(buf_loc)
3636
# read the chunk of data from the file
3737
chunk = np.fromfile(f, dtype=typ, offset=start * typ.itemsize, count=end-start)
38-
39-
return chunk
38+
39+
return chunk
4040

4141
def toTimestamp(serialFormat):
4242
return (serialFormat - 25569) * 86400.0
@@ -45,7 +45,7 @@ def toDatetime(timestamp):
4545
return datetime.utcfromtimestamp(timestamp)
4646

4747
def get_clr(n, name='hsv'):
48-
'''Returns a function that maps each index in 0, 1, ..., n-1 to a distinct
48+
'''Returns a function that maps each index in 0, 1, ..., n-1 to a distinct
4949
RGB color; the keyword argument name must be a standard mpl colormap name.'''
5050
return plt.cm.get_cmap(name, n)
5151

@@ -57,35 +57,35 @@ class Channel:
5757
APReader uses the Channel-Lengths to connect Channels together.
5858
Say there are two Channels with Length 100, then one of those will have "Time" in its name.
5959
The other one then gets a reference to the "time" one.
60-
61-
If there is more than one channel having the same amount of entries, every channel will
60+
61+
If there is more than one channel having the same amount of entries, every channel will
6262
get the same reference to the time channel.
63-
"""
63+
"""
6464
# data: List[float]
6565
verbose: bool
6666
# Defines if data should be filtered.
6767
filterData: bool
68-
68+
6969
# Specifies if channel entries should be loaded in parallel.
7070
parallelLoad: bool
7171
# Amount of parallel processes that can be used to load data.
7272
parallelProcs: int
7373
# The parallel pool which holds parallel processes.
7474
parallelPool: mpPool
75-
75+
7676
def __init__(self, reader: BinaryReader, fileName='unknown', filepath='', \
7777
verbose=False, parallelPool=None):
7878
"""
7979
Creates the Channel.
8080
8181
Uses a reader (BinaryReader) to read the data from the file accessed by "APReader.__init__".
8282
"""
83-
83+
8484
# parallel stuff
8585
self.parallelLoad = parallelPool is not None
8686
self.parallelPool = parallelPool
8787
self.parallelProcs = len(mp.active_children())
88-
88+
8989
# defines, if the apreader should output verbose debug messages
9090
self.verbose = verbose
9191

@@ -108,11 +108,11 @@ def __init__(self, reader: BinaryReader, fileName='unknown', filepath='', \
108108
tName = self.Name.replace(' ',"_") # temporary name
109109
self.fullName = f"{fileName}.{tName}"
110110
self.filePath = filepath
111-
# retrieve unit of channel
112-
111+
# retrieve unit of channel
112+
113113
self.unit = reader.read_string(reader.read_int16())
114-
115-
# get comment of channel
114+
115+
# get comment of channel
116116
self.comment = reader.read_string(reader.read_int16())
117117

118118
# 0: numeric, 1: string, 2: binary object
@@ -125,7 +125,7 @@ def __init__(self, reader: BinaryReader, fileName='unknown', filepath='', \
125125
# extended channel header
126126
self.nHdrBytes = reader.read_int32()
127127
self.extHeader = self.readExtHeader(reader)
128-
128+
129129
precDict = {0:8, 1:4, 2:2} # key: Attribute "Exportformat", value: precision in bytes
130130
try:
131131
self.precision = precDict[self.extHeader['ExportFormat']]
@@ -161,13 +161,13 @@ def readExtHeader(self, rdr: BinaryReader):
161161
values are stored at byte addresses which are integer multiples of their
162162
width in bytes (i.e. doubles are stored on addresses divisible by eight,
163163
floats on addresses divisible by four etc.)
164-
165-
See the link below for more info:
164+
165+
See the link below for more info:
166166
https://stackoverflow.com/questions/4306186/structure-padding-and-packing
167-
167+
168168
For this reason, I've added three bytes of padding before the attribute
169169
'NominalRange', which is a float.
170-
170+
171171
"""
172172
pos0 = rdr.tell() # In general not a multiple of eight, which is unexpected!
173173

@@ -176,41 +176,41 @@ def readExtHeader(self, rdr: BinaryReader):
176176
exthdr['dt'] = rdr.read_double() # 16
177177
exthdr['SensorType'] = rdr.read_int16() # 18
178178
exthdr['SupplyVoltage'] = rdr.read_int16() # 20
179-
179+
180180
exthdr['FiltChar'] = rdr.read_int16() # 22
181181
exthdr['FiltFreq'] = rdr.read_int16() # 24
182182
exthdr['TareVal'] = rdr.read_float() # 28
183-
exthdr['ZeroVal'] = rdr.read_float() # 32
183+
exthdr['ZeroVal'] = rdr.read_float() # 32
184184
exthdr['MeasRange'] = rdr.read_float() # 36
185185
exthdr['InChar'] = [rdr.read_float() for i in range(4)] # 40, 44, 48, 52
186-
186+
187187
exthdr['SerNo'] = rdr.read_string(32) # 84
188188
exthdr['PhysUnit'] = rdr.read_string(8) # 92
189189
exthdr['NativeUnit'] = rdr.read_string(8) # 100
190-
190+
191191
exthdr['Slot'] = rdr.read_int16() # 102
192192
exthdr['SubSlot'] = rdr.read_int16() # 104
193193
exthdr['AmpType'] = rdr.read_int16() # 106
194194
exthdr['APType'] = rdr.read_int16() # 108
195195
exthdr['kFactor'] = rdr.read_float() # 112
196196
exthdr['bFactor'] = rdr.read_float() # 116
197-
197+
198198
exthdr['MeasSig'] = rdr.read_int16() # 118
199199
exthdr['AmpInput'] = rdr.read_int16() # 120
200200
exthdr['HPFilt'] = rdr.read_int16() # 122
201201
exthdr['OLImportInfo'] = rdr.read_byte() # 123
202202
exthdr['ScaleType'] = rdr.read_byte() # 124
203-
exthdr['SoftwareTareVal'] = rdr.read_float() # 128
203+
exthdr['SoftwareTareVal'] = rdr.read_float() # 128
204204
exthdr['WriteProtected'] = rdr.read_byte() # 129
205205
rdr.read_string(3) # 132
206-
207-
exthdr['NominalRange'] = rdr.read_float() # 136
206+
207+
exthdr['NominalRange'] = rdr.read_float() # 136
208208
exthdr['CLCFactor'] = rdr.read_float() # 140
209209
exthdr['ExportFormat'] = rdr.read_byte() # 141
210210
rdr.read_string(7) # 148
211-
# reserve = rdr.read_string(10)
211+
# reserve = rdr.read_string(10)
212212
posN = rdr.tell()
213-
213+
214214
if (posN-pos0) != self.nHdrBytes:
215215
print("""
216216
WARNING:
@@ -224,7 +224,7 @@ def readExtHeader(self, rdr: BinaryReader):
224224
""".format(self.Name))
225225
rdr.seek(pos0 + self.nHdrBytes)
226226
exthdr['ExportFormat'] = 0
227-
227+
228228
return exthdr
229229

230230
def readData(self):
@@ -237,29 +237,29 @@ def readData(self):
237237
# if something was wrong previously, nothing will happen here
238238
if self.broken:
239239
return
240-
240+
241241
# The data is stored channelwise. We therefore only need to pass pointers to the first and last byte.
242242
if self.precision == 8 or self.precision == 4:
243-
datatype = np.dtype('f{}'.format(self.precision))
243+
datatype = np.dtype('f{}'.format(self.precision))
244244
# parallel loading will split up the incoming bin array
245245
if self.parallelLoad:
246246
self.data = self.read_data_parallel(datatype)
247-
247+
248248
# default loading will load all entries at once
249249
else:
250250
self.data = np.fromfile(self.reader.buf, dtype=datatype, count=self.length)
251-
251+
252252
elif self.precision == 2:
253253
MinValue = self.reader.read_double()
254254
MaxValue = self.reader.read_double()
255255
sf = (MaxValue - MinValue)/32767 # scale factor
256256
self.data = np.fromfile(self.reader.buf, dtype=np.dtype('u2'), count=self.length)*sf + MinValue
257-
257+
258258
def __str__(self):
259259
"""
260260
Default conversion to string.
261261
"""
262-
return f'Channel "{self.Name}" ({self.length} Entries)'
262+
return f'Channel "{self.Name}" ({self.length} Entries)'
263263

264264
def __getitem__(self, key) -> float:
265265
"""Return the item at index key.
@@ -271,8 +271,8 @@ def __getitem__(self, key) -> float:
271271
double: self.data[key]
272272
"""
273273
return self.data[key]
274-
275-
def plot(self, governed = False, axes=None, clr='b'):
274+
275+
def plot(self, governed = False, axes=None, clr='b', ls="-"):
276276
"""
277277
Plot the channel over its connected time-channel.
278278
@@ -288,31 +288,31 @@ def plot(self, governed = False, axes=None, clr='b'):
288288

289289
if self.Time is None:
290290
print("\t[ APREAD/PLOT ] Channel does not have time data. Not plotting.")
291-
return
291+
return
292292

293293
plotbase = axes if axes is not None else plt
294-
295-
294+
295+
296296
if self.verbose:
297297
print(f'\t[ APREAD/PLOT ] Plotting {self.Name}')
298-
298+
299299
if not governed:
300300
plt.figure(self.Name)
301301
plt.xlabel('Time [s]')
302302
plt.ylabel(self.unit)
303303

304-
line = plotbase.plot(self.Time.data, self.data, color=clr, label=self.Name )
305-
306-
304+
line = plotbase.plot(self.Time.data, self.data, color=clr, label=self.Name, linestyle=ls)
305+
306+
307307
if not governed:
308308
plt.title(self.Name)
309309
plt.draw()
310-
plt.legend()
310+
plt.legend()
311311
plt.show()
312-
312+
313313
return line
314-
315-
314+
315+
316316

317317
def read_data_parallel(self, dtype):
318318
"""Reads in the underlying binary data using multiple parallel tasks.
@@ -324,8 +324,8 @@ def read_data_parallel(self, dtype):
324324
ndarray: Array of the binary data.
325325
"""
326326
# chunk the total length of this channel
327-
chunk_size = self.length // self.parallelProcs
328-
327+
chunk_size = self.length // self.parallelProcs
328+
329329
# current location of the buffered binary reader
330330
cur_loc = self.reader.tell()
331331

@@ -338,12 +338,12 @@ def read_data_parallel(self, dtype):
338338
r.wait()
339339
if not r.successful():
340340
print('Error in loading task!')
341-
341+
342342
# concatenate the data structure
343343
data = np.empty(self.length, dtype)
344344
for result, (start, end) in zip(results, chunks):
345345
data[start:end] = result.get()
346-
346+
347347
# push the underlying original reader to after the channel items
348348
self.reader.seek(cur_loc + self.length * dtype.itemsize)
349349
return data
@@ -356,7 +356,7 @@ class Group:
356356
Helps calling plot functions..
357357
"""
358358
# all (unsorted) channels in this group
359-
Channels: List[Channel]
359+
Channels: List[Channel]
360360
"""List of all channels"""
361361
# Name of the time channel of this group
362362
Name: str
@@ -384,7 +384,7 @@ def __init__(self, channels: List[Channel], fileName='unknown', verbose=False):
384384
"""Create group of channels.
385385
386386
Args:
387-
channels (list[Channel]): The channels this group is based on.
387+
channels (list[Channel]): The channels this group is based on.
388388
"""
389389
self.verbose = verbose
390390
# save all channels
@@ -440,18 +440,18 @@ def __getitem__(self, key):
440440
double: self.data[key]
441441
"""
442442
return (self.ChannelX[key], [chan[key] for chan in self.ChannelsY])
443-
444-
def __str__(self):
443+
444+
def __str__(self):
445445
return f'Group "{self.Name}" ({len(self.ChannelsY)} Data-channels, {self.ChannelX.length} Entries)'
446-
446+
447447
def plotChannel(self, channelIndex):
448448
"""Plot a specific channel
449449
450450
Args:
451451
channelIndex (int): The index of the channel.
452452
"""
453453
self.plotChannels(channelIndex, channelIndex)
454-
454+
455455
def plotChannels(self, start, end):
456456
"""Plot a range of channels
457457
@@ -460,51 +460,50 @@ def plotChannels(self, start, end):
460460
end (int): Ending index, supports -[index] to mark index from the end.
461461
"""
462462
self.plot(range(start,end))
463-
463+
464464
def plot(self, channelIndices=None, sameAxis = False):
465465
"""
466466
Plots this group of channels.
467-
467+
468468
Args:
469-
channelIndices The starting index of data channels to be plotted.
470-
469+
channelIndices The starting index of data channels to be plotted.
470+
471471
Examples:
472472
grp.plot() will plot all channels
473473
grp.plot([0]) will plot the first data channel
474-
grp.plot([0, 1, 3]) will plot the first, second and third data channel
474+
grp.plot([0, 1, 3]) will plot the first, second and third data channel
475475
"""
476476
fig, ax1 = plt.subplots()
477477
ax1.set_xlabel(self.ChannelX.unit)
478-
479-
478+
479+
480480
if channelIndices is None:
481-
channels = self.ChannelsY
481+
channels = self.ChannelsY
482482
else:
483483
channels = [self.ChannelsY[x] for x in channelIndices]
484-
484+
485485
# create colormap
486486
cmap = get_clr(len(channels)+1)
487487
# save labels to retrieve them afterwards when building legend
488488
lns = []
489-
489+
490490
axis = ax1
491-
for i,channel in enumerate(channels):
491+
for i,channel in enumerate(channels):
492492
if i > 0 and not sameAxis:
493493
axis = ax1.twinx()
494-
axis.spines['right'].set_position(('outward', 60*(i-1)))
494+
axis.spines['right'].set_position(('outward', 60*(i-1)))
495495
axis.set_ylabel(channel.unit)
496496
axis.tick_params(axis='y', colors=cmap(i))
497-
axis.get_yaxis().label.set_color(cmap(i))
498-
497+
axis.get_yaxis().label.set_color(cmap(i))
498+
499499
chanLine = channel.plot(governed=True, clr=cmap(i))
500-
500+
501501
lns += chanLine
502502

503503
labs = [l.get_label() for l in lns]
504504
ax1.legend(lns, labs, loc=0)
505505
ax1.grid()
506-
506+
507507
plt.title(self.Name)
508508
plt.draw()
509509
plt.show()
510-

0 commit comments

Comments
 (0)