Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/scipy/io/matlab/_mio.py: 5%

65 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-03 06:39 +0000

1""" 

2Module for reading and writing matlab (TM) .mat files 

3""" 

4# Authors: Travis Oliphant, Matthew Brett 

5 

6from contextlib import contextmanager 

7 

8from ._miobase import _get_matfile_version, docfiller 

9from ._mio4 import MatFile4Reader, MatFile4Writer 

10from ._mio5 import MatFile5Reader, MatFile5Writer 

11 

12__all__ = ['mat_reader_factory', 'loadmat', 'savemat', 'whosmat'] 

13 

14 

15@contextmanager 

16def _open_file_context(file_like, appendmat, mode='rb'): 

17 f, opened = _open_file(file_like, appendmat, mode) 

18 try: 

19 yield f 

20 finally: 

21 if opened: 

22 f.close() 

23 

24 

25def _open_file(file_like, appendmat, mode='rb'): 

26 """ 

27 Open `file_like` and return as file-like object. First, check if object is 

28 already file-like; if so, return it as-is. Otherwise, try to pass it 

29 to open(). If that fails, and `file_like` is a string, and `appendmat` is true, 

30 append '.mat' and try again. 

31 """ 

32 reqs = {'read'} if set(mode) & set('r+') else set() 

33 if set(mode) & set('wax+'): 

34 reqs.add('write') 

35 if reqs.issubset(dir(file_like)): 

36 return file_like, False 

37 

38 try: 

39 return open(file_like, mode), True 

40 except OSError as e: 

41 # Probably "not found" 

42 if isinstance(file_like, str): 

43 if appendmat and not file_like.endswith('.mat'): 

44 file_like += '.mat' 

45 return open(file_like, mode), True 

46 else: 

47 raise OSError( 

48 'Reader needs file name or open file-like object' 

49 ) from e 

50 

51 

52@docfiller 

53def mat_reader_factory(file_name, appendmat=True, **kwargs): 

54 """ 

55 Create reader for matlab .mat format files. 

56 

57 Parameters 

58 ---------- 

59 %(file_arg)s 

60 %(append_arg)s 

61 %(load_args)s 

62 %(struct_arg)s 

63 

64 Returns 

65 ------- 

66 matreader : MatFileReader object 

67 Initialized instance of MatFileReader class matching the mat file 

68 type detected in `filename`. 

69 file_opened : bool 

70 Whether the file was opened by this routine. 

71 

72 """ 

73 byte_stream, file_opened = _open_file(file_name, appendmat) 

74 mjv, mnv = _get_matfile_version(byte_stream) 

75 if mjv == 0: 

76 return MatFile4Reader(byte_stream, **kwargs), file_opened 

77 elif mjv == 1: 

78 return MatFile5Reader(byte_stream, **kwargs), file_opened 

79 elif mjv == 2: 

80 raise NotImplementedError('Please use HDF reader for matlab v7.3 ' 

81 'files, e.g. h5py') 

82 else: 

83 raise TypeError('Did not recognize version %s' % mjv) 

84 

85 

86@docfiller 

87def loadmat(file_name, mdict=None, appendmat=True, **kwargs): 

88 """ 

89 Load MATLAB file. 

90 

91 Parameters 

92 ---------- 

93 file_name : str 

94 Name of the mat file (do not need .mat extension if 

95 appendmat==True). Can also pass open file-like object. 

96 mdict : dict, optional 

97 Dictionary in which to insert matfile variables. 

98 appendmat : bool, optional 

99 True to append the .mat extension to the end of the given 

100 filename, if not already present. Default is True. 

101 byte_order : str or None, optional 

102 None by default, implying byte order guessed from mat 

103 file. Otherwise can be one of ('native', '=', 'little', '<', 

104 'BIG', '>'). 

105 mat_dtype : bool, optional 

106 If True, return arrays in same dtype as would be loaded into 

107 MATLAB (instead of the dtype with which they are saved). 

108 squeeze_me : bool, optional 

109 Whether to squeeze unit matrix dimensions or not. 

110 chars_as_strings : bool, optional 

111 Whether to convert char arrays to string arrays. 

112 matlab_compatible : bool, optional 

113 Returns matrices as would be loaded by MATLAB (implies 

114 squeeze_me=False, chars_as_strings=False, mat_dtype=True, 

115 struct_as_record=True). 

116 struct_as_record : bool, optional 

117 Whether to load MATLAB structs as NumPy record arrays, or as 

118 old-style NumPy arrays with dtype=object. Setting this flag to 

119 False replicates the behavior of scipy version 0.7.x (returning 

120 NumPy object arrays). The default setting is True, because it 

121 allows easier round-trip load and save of MATLAB files. 

122 verify_compressed_data_integrity : bool, optional 

123 Whether the length of compressed sequences in the MATLAB file 

124 should be checked, to ensure that they are not longer than we expect. 

125 It is advisable to enable this (the default) because overlong 

126 compressed sequences in MATLAB files generally indicate that the 

127 files have experienced some sort of corruption. 

128 variable_names : None or sequence 

129 If None (the default) - read all variables in file. Otherwise, 

130 `variable_names` should be a sequence of strings, giving names of the 

131 MATLAB variables to read from the file. The reader will skip any 

132 variable with a name not in this sequence, possibly saving some read 

133 processing. 

134 simplify_cells : False, optional 

135 If True, return a simplified dict structure (which is useful if the mat 

136 file contains cell arrays). Note that this only affects the structure 

137 of the result and not its contents (which is identical for both output 

138 structures). If True, this automatically sets `struct_as_record` to 

139 False and `squeeze_me` to True, which is required to simplify cells. 

140 

141 Returns 

142 ------- 

143 mat_dict : dict 

144 dictionary with variable names as keys, and loaded matrices as 

145 values. 

146 

147 Notes 

148 ----- 

149 v4 (Level 1.0), v6 and v7 to 7.2 matfiles are supported. 

150 

151 You will need an HDF5 Python library to read MATLAB 7.3 format mat 

152 files. Because SciPy does not supply one, we do not implement the 

153 HDF5 / 7.3 interface here. 

154 

155 Examples 

156 -------- 

157 >>> from os.path import dirname, join as pjoin 

158 >>> import scipy.io as sio 

159 

160 Get the filename for an example .mat file from the tests/data directory. 

161 

162 >>> data_dir = pjoin(dirname(sio.__file__), 'matlab', 'tests', 'data') 

163 >>> mat_fname = pjoin(data_dir, 'testdouble_7.4_GLNX86.mat') 

164 

165 Load the .mat file contents. 

166 

167 >>> mat_contents = sio.loadmat(mat_fname) 

168 

169 The result is a dictionary, one key/value pair for each variable: 

170 

171 >>> sorted(mat_contents.keys()) 

172 ['__globals__', '__header__', '__version__', 'testdouble'] 

173 >>> mat_contents['testdouble'] 

174 array([[0. , 0.78539816, 1.57079633, 2.35619449, 3.14159265, 

175 3.92699082, 4.71238898, 5.49778714, 6.28318531]]) 

176 

177 By default SciPy reads MATLAB structs as structured NumPy arrays where the 

178 dtype fields are of type `object` and the names correspond to the MATLAB 

179 struct field names. This can be disabled by setting the optional argument 

180 `struct_as_record=False`. 

181 

182 Get the filename for an example .mat file that contains a MATLAB struct 

183 called `teststruct` and load the contents. 

184 

185 >>> matstruct_fname = pjoin(data_dir, 'teststruct_7.4_GLNX86.mat') 

186 >>> matstruct_contents = sio.loadmat(matstruct_fname) 

187 >>> teststruct = matstruct_contents['teststruct'] 

188 >>> teststruct.dtype 

189 dtype([('stringfield', 'O'), ('doublefield', 'O'), ('complexfield', 'O')]) 

190 

191 The size of the structured array is the size of the MATLAB struct, not the 

192 number of elements in any particular field. The shape defaults to 2-D 

193 unless the optional argument `squeeze_me=True`, in which case all length 1 

194 dimensions are removed. 

195 

196 >>> teststruct.size 

197 1 

198 >>> teststruct.shape 

199 (1, 1) 

200 

201 Get the 'stringfield' of the first element in the MATLAB struct. 

202 

203 >>> teststruct[0, 0]['stringfield'] 

204 array(['Rats live on no evil star.'], 

205 dtype='<U26') 

206 

207 Get the first element of the 'doublefield'. 

208 

209 >>> teststruct['doublefield'][0, 0] 

210 array([[ 1.41421356, 2.71828183, 3.14159265]]) 

211 

212 Load the MATLAB struct, squeezing out length 1 dimensions, and get the item 

213 from the 'complexfield'. 

214 

215 >>> matstruct_squeezed = sio.loadmat(matstruct_fname, squeeze_me=True) 

216 >>> matstruct_squeezed['teststruct'].shape 

217 () 

218 >>> matstruct_squeezed['teststruct']['complexfield'].shape 

219 () 

220 >>> matstruct_squeezed['teststruct']['complexfield'].item() 

221 array([ 1.41421356+1.41421356j, 2.71828183+2.71828183j, 

222 3.14159265+3.14159265j]) 

223 """ 

224 variable_names = kwargs.pop('variable_names', None) 

225 with _open_file_context(file_name, appendmat) as f: 

226 MR, _ = mat_reader_factory(f, **kwargs) 

227 matfile_dict = MR.get_variables(variable_names) 

228 

229 if mdict is not None: 

230 mdict.update(matfile_dict) 

231 else: 

232 mdict = matfile_dict 

233 

234 return mdict 

235 

236 

237@docfiller 

238def savemat(file_name, mdict, 

239 appendmat=True, 

240 format='5', 

241 long_field_names=False, 

242 do_compression=False, 

243 oned_as='row'): 

244 """ 

245 Save a dictionary of names and arrays into a MATLAB-style .mat file. 

246 

247 This saves the array objects in the given dictionary to a MATLAB- 

248 style .mat file. 

249 

250 Parameters 

251 ---------- 

252 file_name : str or file-like object 

253 Name of the .mat file (.mat extension not needed if ``appendmat == 

254 True``). 

255 Can also pass open file_like object. 

256 mdict : dict 

257 Dictionary from which to save matfile variables. 

258 appendmat : bool, optional 

259 True (the default) to append the .mat extension to the end of the 

260 given filename, if not already present. 

261 format : {'5', '4'}, string, optional 

262 '5' (the default) for MATLAB 5 and up (to 7.2), 

263 '4' for MATLAB 4 .mat files. 

264 long_field_names : bool, optional 

265 False (the default) - maximum field name length in a structure is 

266 31 characters which is the documented maximum length. 

267 True - maximum field name length in a structure is 63 characters 

268 which works for MATLAB 7.6+. 

269 do_compression : bool, optional 

270 Whether or not to compress matrices on write. Default is False. 

271 oned_as : {'row', 'column'}, optional 

272 If 'column', write 1-D NumPy arrays as column vectors. 

273 If 'row', write 1-D NumPy arrays as row vectors. 

274 

275 Examples 

276 -------- 

277 >>> from scipy.io import savemat 

278 >>> import numpy as np 

279 >>> a = np.arange(20) 

280 >>> mdic = {"a": a, "label": "experiment"} 

281 >>> mdic 

282 {'a': array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 

283 17, 18, 19]), 

284 'label': 'experiment'} 

285 >>> savemat("matlab_matrix.mat", mdic) 

286 """ 

287 with _open_file_context(file_name, appendmat, 'wb') as file_stream: 

288 if format == '4': 

289 if long_field_names: 

290 message = "Long field names are not available for version 4 files" 

291 raise ValueError(message) 

292 MW = MatFile4Writer(file_stream, oned_as) 

293 elif format == '5': 

294 MW = MatFile5Writer(file_stream, 

295 do_compression=do_compression, 

296 unicode_strings=True, 

297 long_field_names=long_field_names, 

298 oned_as=oned_as) 

299 else: 

300 raise ValueError("Format should be '4' or '5'") 

301 MW.put_variables(mdict) 

302 

303 

304@docfiller 

305def whosmat(file_name, appendmat=True, **kwargs): 

306 """ 

307 List variables inside a MATLAB file. 

308 

309 Parameters 

310 ---------- 

311 %(file_arg)s 

312 %(append_arg)s 

313 %(load_args)s 

314 %(struct_arg)s 

315 

316 Returns 

317 ------- 

318 variables : list of tuples 

319 A list of tuples, where each tuple holds the matrix name (a string), 

320 its shape (tuple of ints), and its data class (a string). 

321 Possible data classes are: int8, uint8, int16, uint16, int32, uint32, 

322 int64, uint64, single, double, cell, struct, object, char, sparse, 

323 function, opaque, logical, unknown. 

324 

325 Notes 

326 ----- 

327 v4 (Level 1.0), v6 and v7 to 7.2 matfiles are supported. 

328 

329 You will need an HDF5 python library to read matlab 7.3 format mat 

330 files (e.g. h5py). Because SciPy does not supply one, we do not implement the 

331 HDF5 / 7.3 interface here. 

332 

333 .. versionadded:: 0.12.0 

334 

335 Examples 

336 -------- 

337 >>> from io import BytesIO 

338 >>> import numpy as np 

339 >>> from scipy.io import savemat, whosmat 

340 

341 Create some arrays, and use `savemat` to write them to a ``BytesIO`` 

342 instance. 

343 

344 >>> a = np.array([[10, 20, 30], [11, 21, 31]], dtype=np.int32) 

345 >>> b = np.geomspace(1, 10, 5) 

346 >>> f = BytesIO() 

347 >>> savemat(f, {'a': a, 'b': b}) 

348 

349 Use `whosmat` to inspect ``f``. Each tuple in the output list gives 

350 the name, shape and data type of the array in ``f``. 

351 

352 >>> whosmat(f) 

353 [('a', (2, 3), 'int32'), ('b', (1, 5), 'double')] 

354 

355 """ 

356 with _open_file_context(file_name, appendmat) as f: 

357 ML, file_opened = mat_reader_factory(f, **kwargs) 

358 variables = ML.list_variables() 

359 return variables