1#!/usr/local/bin/python3.8 2 3# python3 status: compatible 4 5# system libraries 6import sys, os, glob 7 8# AFNI libraries 9from afnipy import option_list as OL 10from afnipy import afni_util as UTIL 11from afnipy import lib_afni1D as LD 12 13# ---------------------------------------------------------------------- 14# globals 15 16g_help_string = """ 17============================================================================= 18read_matlab_files.py - describe or convert MATLAB files (to 1D) 19 20 Describe the contents of matlab files, and possibly convert them to 1D. 21 22 Using only -infiles, all file objects (names not starting with '__') will 23 be reported. With the addition of -prefix, all numpy matrices will be 24 converted to 1D format. 25 26------------------------------------------ 27examples: 28 29 1. Describe the contents of all matlab files. 30 31 read_matlab_files.py -infiles *.mat 32 33 1. Convert all matlab files in the current directory to test.*.1D 34 35 read_matlab_files.py -infiles *.mat -prefix test 36 37------------------------------------------ 38terminal options: 39 40 -help : show this help 41 -hist : show the revision history 42 -ver : show the version number 43 44------------------------------------------ 45process options: 46 47 -infiles : specify input files 48 -overwrite : overwrite any output file 49 -prefix PREFIX : prefix for output file names 50 51 Using -prefix, output files will have the naming format: 52 53 PREFIX.INDEX.KEY.1D 54 55 PREFIX : as specified with -prefix 56 INDEX : 1-based index of objects found in file 57 KEY : key (label) corresponding to the given object 58 59------------------------------------------ 60R Reynolds January 2015 61============================================================================= 62""" 63 64g_todo = """ 65 todo list: 66""" 67 68g_history = """ 69 read_matlab_files.py history: 70 71 0.0 Jan 14, 2015 - initial version 72 0.1 May 11, 2020 - python3 compatible 73""" 74 75g_version = "read_matlab_files.py version 0.1, May 11, 2020" 76 77 78class MyInterface: 79 """interface class for MyLibrary (whatever that is) 80 """ 81 def __init__(self, verb=1): 82 # main variables 83 self.valid_opts = None 84 self.user_opts = None 85 86 # control 87 self.verb = 1 88 89 # process vars 90 self.infiles = [] 91 self.prefix = '' 92 self.overwrite = 0 93 94 # initialize valid_opts 95 self.valid_opts = self.get_valid_opts() 96 97 def get_valid_opts(self): 98 vopts = OL.OptionList('valid opts') 99 100 # short, terminal arguments 101 vopts.add_opt('-help', 0, [], helpstr='display program help') 102 vopts.add_opt('-hist', 0, [], helpstr='display the modification history') 103 vopts.add_opt('-ver', 0, [], helpstr='display the current version number') 104 105 # general options 106 vopts.add_opt('-infiles', -1, [], 107 helpstr='specify input files') 108 vopts.add_opt('-overwrite', 0, [], 109 helpstr='flag to overwrite any existing output files') 110 vopts.add_opt('-prefix', 1, [], 111 helpstr='specify prefix for output files') 112 vopts.add_opt('-verb', 1, [], helpstr='set the verbose level (def=1)') 113 114 vopts.sort() 115 116 return vopts 117 118 def process_options(self): 119 """return 1 on valid and exit 120 return 0 on valid and continue 121 return -1 on invalid 122 """ 123 124 argv = sys.argv 125 126 # process any optlist_ options 127 self.valid_opts.check_special_opts(argv) 128 129 # process terminal options without the option_list interface 130 # (so that errors are not reported) 131 132 # if no arguments are given, do default processing 133 if '-help' in argv or len(argv) < 2: 134 print(g_help_string) 135 return 1 136 137 if '-hist' in argv: 138 print(g_history) 139 return 1 140 141 if '-show_valid_opts' in argv: 142 self.valid_opts.show('', 1) 143 return 1 144 145 if '-ver' in argv: 146 print(g_version) 147 return 1 148 149 # ============================================================ 150 # read options specified by the user 151 self.user_opts = OL.read_options(argv, self.valid_opts) 152 uopts = self.user_opts # convenience variable 153 if not uopts: return -1 # error condition 154 155 # ------------------------------------------------------------ 156 # process verb first 157 158 val, err = uopts.get_type_opt(int, '-verb') 159 if val != None and not err: self.verb = val 160 161 # ------------------------------------------------------------ 162 # process options sequentially, to make them like a script 163 errs = 0 164 for opt in self.user_opts.olist: 165 # check for anything to skip 166 if opt.name == '-verb': pass 167 168 elif opt.name == '-infiles': 169 self.infiles, err = uopts.get_string_list('', opt=opt) 170 if self.infiles == None or err: 171 print('** failed to read -infiles list') 172 errs +=1 173 174 elif opt.name == '-overwrite': 175 self.overwrite = 1 176 177 elif opt.name == '-prefix': 178 val, err = uopts.get_string_opt(opt=opt) 179 if val != None and not err: self.prefix = val 180 181 # allow early and late error returns 182 if errs: return -1 183 184 # ------------------------------------------------------------ 185 # apply any trailing logic 186 187 # if here, require input files 188 if len(self.infiles) < 1: 189 print('** missing -infiles option') 190 errs += 1 191 192 # if no -prefix and no -verb, default verb to 2 193 if not self.user_opts.find_opt('-verb') and self.prefix == '': 194 self.verb = 2 195 196 if errs: return -1 197 198 return 0 199 200 def process_matlab_file(self, fname, index=0): 201 """process matlab files 202 """ 203 204 try: 205 import scipy.io 206 import numpy 207 except: 208 print('** missing library: scipy.io') 209 print(' (please install scipy)') 210 return 1 211 212 if not os.path.isfile(fname): 213 print("** missing file '%s'" % fname) 214 return 1 215 216 mfile = scipy.io.loadmat(fname) 217 if mfile == None: return 1 218 219 # prepare output prefix 220 prefix = self.prefix 221 if prefix != '' and len(self.infiles) > 1: 222 prefix = '%s.%02d' % (self.prefix, index+1) 223 224 klist = [key for key in list(mfile.keys()) if key[0:2] != '__'] 225 maxlen = max([len(key) for key in klist]) 226 227 if self.verb: 228 if self.verb > 1: print() 229 print('-- file %s has %d key(s)' % (fname, len(klist))) 230 231 for key in klist: 232 obj = mfile[key] 233 if self.verb > 1: 234 if type(obj) is numpy.ndarray: 235 shstr = ' shape %s' % str(obj.shape) 236 else: 237 shstr = '' 238 print(' %-*s %s%s' % (maxlen, key, type(obj), shstr)) 239 240 # maybe write any numpy data 241 if prefix != '' and type(obj) is numpy.ndarray: 242 # convert object to Afni1D and transpose 243 olist = obj.tolist() 244 adata = LD.Afni1D(from_mat=1, matrix=olist, verb=self.verb) 245 adata.transpose() 246 247 # if model, break apart, else just write 248 if key == 'model' and adata.nvec >= 2: 249 self.write_model_files(adata, prefix) 250 else: 251 ofile = '%s.%s.1D'%(prefix,key) 252 print('++ writing ndarry to %s' % ofile) 253 adata.write(ofile, overwrite=self.overwrite) 254 255 return 0 256 257 def write_model_files(self, adata, prefix): 258 """break model matrix into many 1D files 259 """ 260 261 if adata.nvec < 1: return 0 262 263 for ind in range(adata.nvec): 264 avec = LD.Afni1D(from_mat=1, matrix=[adata.mat[ind]], verb=self.verb) 265 ofile = '%s.model.%02d.1D' % (prefix, ind+1) 266 print('++ writing model file %s' % ofile) 267 avec.write(ofile, overwrite=self.overwrite) 268 269 return 0 270 271 def process_files(self): 272 """process matlab files 273 """ 274 275 print('-- have %d files to process' % len(self.infiles)) 276 277 # check file existence first 278 for ind, ifile in enumerate(self.infiles): 279 if self.process_matlab_file(ifile, ind): return 1 280 281 return 0 282 283def main(): 284 me = MyInterface() 285 if not me: return 1 286 287 rv = me.process_options() 288 if rv > 0: return 0 # exit with success 289 if rv < 0: # exit with error status 290 print('** failed to process options...') 291 return 1 292 293 if me.process_files(): return 1 294 295 return 0 296 297if __name__ == '__main__': 298 sys.exit(main()) 299 300 301