forked from ratal/mdfreader
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mdfreaderui.py
336 lines (312 loc) · 14.2 KB
/
mdfreaderui.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
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# -*- coding: utf-8 -*-
"""
Module implementing MainWindow.
"""
from PyQt4.QtGui import QMainWindow, QFileDialog, QAction
from PyQt4.QtCore import pyqtSignature, SIGNAL
from Ui_mdfreaderui import Ui_MainWindow
from io import open
from multiprocessing import Pool,cpu_count
from mdfreader import mdfinfo,mdf
from sys import version_info
from os import path
PythonVersion=version_info
PythonVersion=PythonVersion[0]
MultiProc=True # multiprocess switch, for debug purpose put False
class MainWindow(QMainWindow, Ui_MainWindow, QFileDialog):
"""
Class documentation goes here.
"""
def __init__(self, parent = None):
"""
Constructor
"""
QMainWindow.__init__(self, parent)
self.setupUi(self)
self.fileNames=[] # files to convert
self.mdfClass=mdf() # instance of mdf
self.mdfinfoClass=mdfinfo() # instance of mdfinfo
self.convertSelection='Matlab' # by default Matlab conversion is selected
self.MergeFiles=False # by default
self.labFileName=[] # .lab file name
self.defaultPath=None # default path to open for browsing files
self.actionPlotSelectedChannel = QAction("Plot", self.SelectedChannelList) # context menu to allow plot of channel
self.SelectedChannelList.addAction(self.actionPlotSelectedChannel )
self.connect(self.actionPlotSelectedChannel, SIGNAL("triggered()"), self.plotSelected)
self.actionPlotChannel = QAction("Plot", self.channelList) # context menu to allow plot of channel
self.channelList.addAction(self.actionPlotChannel)
self.connect(self.actionPlotChannel, SIGNAL("triggered()"), self.plot)
self.actionFileRemove= QAction("Delete", self.FileList) # context menu to remove selected file from list
self.FileList.addAction(self.actionFileRemove)
self.connect(self.actionFileRemove, SIGNAL("triggered()"), self.FileRemove)
@pyqtSignature("")
def on_browse_clicked(self):
"""
Will open a dialog to browse for files
"""
if self.defaultPath==None:
self.fileNames=QFileDialog.getOpenFileNames(self, "Select Measurement Files",filter=("MDF file (*.dat *.mdf *.mf4)"))
self.defaultPath=path.dirname(str(self.fileNames[0]))
else:
self.fileNames=QFileDialog.getOpenFileNames(self, "Select Measurement Files",self.defaultPath, filter=("MDF file (*.dat *.mdf *.mf4)"))
if not len(self.fileNames)==0:
self.FileList.addItems(self.fileNames)
self.mdfinfoClass.__init__()
self.cleanChannelList()
self.cleanSelectedChannelList()
ChannelList=convertChannelList(self.mdfinfoClass.listChannels(str(self.fileNames[0])))
self.SelectedChannelList.addItems(ChannelList)
self.FileList.setItemSelected(self.FileList.item(0), True)
def cleanSelectedChannelList(self):
# remove all items from list
self.SelectedChannelList.clear()
[self.SelectedChannelList.takeItem(0) for i in range(self.SelectedChannelList.count())]
def cleanChannelList(self):
# remove all items from list
self.channelList.clear()
[self.channelList.takeItem(0) for i in range(self.channelList.count())]
@pyqtSignature("")
def on_Convert_clicked(self):
"""
Will convert mdf files into selected format
"""
# create list of channels to be converted for all files
channelList=[]
[channelList.append(str(self.SelectedChannelList.item(i).text())) for i in range(self.SelectedChannelList.count())]
channelList=list(set(channelList)) # remove duplicates
# Process all mdf files recursively
if self.FileList.count()>0: # not empty list
ncpu=cpu_count() # to still have response from PC
if ncpu<1:
ncpu=1
pool = Pool(processes=ncpu)
if self.MergeFiles or self.FileList.count()<2: # export all files separately, inverted bool
convertFlag=True
convertSelection=self.convertSelection
resampleValue=float(self.resampleValue.text())
#re-sample if requested
if self.resample.checkState():
if not len(self.resampleValue.text())==0:
resampleFlag=True
else:
print('Empty field for resampling')
raise
else:
resampleFlag=False
args=[(str(self.FileList.takeItem(0).text()),channelList,resampleFlag,resampleValue,convertFlag,convertSelection) for i in range(self.FileList.count())]
if MultiProc:
result=pool.map_async(processMDFstar,args)
result.get() # waits until finished
else:
result=list(map(processMDFstar,args))
self.cleanChannelList()
elif self.FileList.count()>=2: # Stack files data if min 2 files in list
# import first file
fileNameList=[]
if len(self.resampleValue.text())==0:
print('Wrong value for re-sampling')
raise
convertFlag=False
convertSelection=self.convertSelection
resampleValue=float(self.resampleValue.text())
resampleFlag=True # always re-sample when merging
fileName=str(self.FileList.item(0).text()) # Uses first file name for the converted file
# list filenames
args=[(str(self.FileList.takeItem(0).text()),channelList,resampleFlag,resampleValue,convertFlag,convertSelection) for i in range(self.FileList.count())]
if MultiProc:
res=pool.map_async(processMDFstar,args)
result=res.get()
else:
result=map(processMDFstar,args) # no multiprocess, for debug
# Merge results
self.mdfClass.__init__() # clear memory
self.mdfClass.fileName=fileName #First filename will be used for exported file name
self.mdfClass.multiProc=False # do not use multiproc inside mdfreader while already using from mdfreaderui level
buffer=self.mdfClass.copy() # create/copy empty class in buffer
res=result.pop(0) # extract first file data from processed list
self.mdfClass.update(res[0]) # initialize mdfclass wih first file data
self.mdfClass.masterChannelList=res[1] # initialize masterChannelList
fileNameList.append(res[2]) # record merged file in list
for res in result: # Merge
buffer.__init__() # clean buffer class
buffer.update(res[0]) # assigns next class to buffer
buffer.masterChannelList=res[1]
fileNameList.append(res[2])
self.mdfClass.mergeMdf(buffer) # merge buffer to merged class mdfClass
# Export
if self.convertSelection=='Matlab':
self.mdfClass.exportToMatlab()
elif self.convertSelection=='csv':
self.mdfClass.exportToCSV()
elif self.convertSelection=='netcdf':
self.mdfClass.exportToNetCDF()
elif self.convertSelection=='hdf5':
self.mdfClass.exportToHDF5()
elif self.convertSelection=='excel':
self.mdfClass.exportToExcel()
elif self.convertSelection=='excel2010':
self.mdfClass.exportToXlsx()
elif self.convertSelection=='mdf3':
self.mdfClass.write(fileName+'_new')
self.cleanChannelList()
print('File list merged :')
for file in fileNameList: # prints files merged for checking
print(file)
self.mdfClass.__init__() # clear memory
@pyqtSignature("QListWidgetItem*")
def on_FileList_itemClicked(self, item):
"""
If user click on file list
"""
# Refresh list of channels from selected file
self.mdfinfoClass.__init__()
#self.mdfinfoClass.readinfo(item)
self.cleanChannelList()
ChannelList=convertChannelList(self.mdfinfoClass.listChannels(str(item.text())))
self.channelList.addItems(ChannelList)
self.mdfinfoClass.__init__() # clean object to free memory
@pyqtSignature("bool")
def on_matlab_clicked(self, checked):
"""
Selects Matlab conversion
"""
self.convertSelection='Matlab'
@pyqtSignature("bool")
def on_netcdf_clicked(self, checked):
"""
Selects netcdf conversion.
"""
self.convertSelection='netcdf'
@pyqtSignature("bool")
def on_hdf5_clicked(self, checked):
"""
Selects hdf5 conversion.
"""
self.convertSelection='hdf5'
@pyqtSignature("bool")
def on_csv_clicked(self, checked):
"""
Selects csv conversion.
"""
self.convertSelection='csv'
@pyqtSignature("bool")
def on_excel_clicked(self, checked):
"""
Selects excel conversion.
"""
self.convertSelection='excel'
@pyqtSignature("bool")
def on_excel2010_clicked(self, checked):
"""
Selects excel conversion.
"""
self.convertSelection='excel2010'
@pyqtSignature("bool")
def on_mdf3_clicked(self, checked):
"""
Selects MDF3.3 conversion.
"""
self.convertSelection='mdf3'
@pyqtSignature("")
def on_LabFileBrowse_clicked(self):
"""
selects lab file from browser.
"""
self.labFileName=QFileDialog.getOpenFileName(self, "Select Lab Files", filter=("Lab file (*.lab)"))
if not len(self.labFileName)==0:
self.LabFile.del_() # clear linedit
self.LabFile.insert(str(self.labFileName)) # replace linedit field by browsed file name
# read lab file
labfile=open(str(self.labFileName), 'r')
self.labChannelList=[]
line = labfile.readline() # read first line [lab]
while 1:
line = labfile.readline()
if not line:
break
self.labChannelList.append(line.replace('\n',''))
self.cleanSelectedChannelList() # Clear Selected file list
self.SelectedChannelList.addItems(self.labChannelList)
def plot(self):
#Finds selected file and read it
selectedFile=self.FileList.selectedItems()
self.mdfClass.__init__(str(selectedFile[0].text())) # read file
# list items selected in listWidget
Channels=self.channelList.selectedItems()
selectedChannels=[]
[selectedChannels.append(str(Channels[i].text())) for i in range(len(Channels))]
# plot channels
self.mdfClass.plot(selectedChannels)
def plotSelected(self):
# plots channels from selected list
selectedFile=self.FileList.selectedItems()
if not len(selectedFile)==0:
self.mdfClass.__init__(str(selectedFile[0].text())) # read file
else:
self.mdfClass.__init__(str(self.FileList[0].text())) # read file
# list items selected in listWidget
Channels=self.SelectedChannelList.selectedItems()
selectedChannels=[]
[selectedChannels.append(str(Channels[i].text())) for i in range(len(Channels))]
# plot channels
self.mdfClass.plot(selectedChannels)
def FileRemove(self):
# removes selected file
selectionList=self.FileList.selectedItems()
[self.FileList.takeItem(self.FileList.row(selectionList[i])) for i in range(len(selectionList))]
def on_SelectedChannelList_dropEvent(self):
# avoids to have duplicates in list when channel is dropped
channelList=[]
[channelList.append(str(self.SelectedChannelList.item(i).text())) for i in range(self.SelectedChannelList.count())]
channelList=list(set( channelList)) # removeDuplicates
self.SelectedChannelList.clear()
self.SelectedChannelList.addItems(channelList)
@pyqtSignature("bool")
def on_MergeFiles_toggled(self, checked):
"""
Slot documentation goes here.
"""
# toggle flag to merge files
self.MergeFiles= not self.MergeFiles
if self.MergeFiles:
self.resample.setCheckState(2)
def processMDF(fileName,channelist,resampleFlag,resampleValue,convertFlag,convertSelection):
# Will process file according to defined options
yop=mdf()
yop.multiProc=False # already multiprocessed
yop.convertAfterRead = True
yop.read(fileName) # reads complete file
yop.keepChannels(channelist) # removes unnecessary channels
if resampleFlag:
yop.resample(resampleValue)
if convertFlag:
if convertSelection=='Matlab':
yop.exportToMatlab()
elif convertSelection=='csv':
yop.exportToCSV()
elif convertSelection=='netcdf':
yop.exportToNetCDF()
elif convertSelection=='hdf5':
yop.exportToHDF5()
elif convertSelection=='excel':
yop.exportToExcel()
elif convertSelection=='excel2010':
yop.exportToXlsx()
elif convertSelection=='mdf3':
yop.write(fileName+'_new')
yopPicklable={} # picklable dict and not object
for channel in list(yop.keys()):
yopPicklable[channel]=yop[channel]
return [yopPicklable,yop.masterChannelList, yop.fileName]
def processMDFstar(args):
try:
return processMDF(*args)
except :
print('Error, following file might be corrupted : '+args[0]) # Shows fileName and parameters to help finding corrupted files
print('Please re-try by removing this file from the list and restart mdfconverter to kill processes and clean memory')
raise # produce error and stops all processes
def convertChannelList(channelList):
if PythonVersion<3:
return [str(name) for name in channelList]
else:
return [(name) for name in channelList]