Coverage for src / thunderfish / hopkinsloader.py: 0%

88 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-15 17:50 +0000

1"""Load EODs from Hopkins files. 

2 

3Carl Hopkins and John Sullivan stored only a few cut-out EOD waveforms 

4of Mormyrid EODs in a specific mat file. These recordings are 

5available at the Macaulay library. 

6 

7## Functions 

8 

9- `load_hopkins()`: load a Hopkins file containing a few EOD pulses. 

10- `analyse_hopkins()`: analyze the content of Hopkins files. 

11 

12""" 

13 

14import sys 

15import numpy as np 

16import matplotlib.pyplot as plt 

17 

18from scipy.io import loadmat 

19from audioio import print_metadata 

20 

21 

22def load_hopkins(file_path): 

23 """ Load a Hopkins file containing a few EOD pulses. 

24 

25 Parameters 

26 ---------- 

27 file_path: str 

28 The mat file with the data. 

29 

30 Returns 

31 ------- 

32 data: list of 2-D ndarrays 

33 A list of single EOD pulses. 

34 First column is time in seconds, second column EOD waveform. 

35 md: nested dict 

36 Metadata. 

37 

38 Raises 

39 ------ 

40 FileNotFoundError 

41 `file_path` does not exist. 

42 ValueError 

43 `file_path` is not a valid mat file. 

44 """ 

45 x = loadmat(file_path, squeeze_me=True) 

46 if not 'eod' in x or not hasattr(x['eod'], 'size'): 

47 return [], {} 

48 y = x['eod'].reshape(x['eod'].size) 

49 if not 'wave' in y.dtype.names or not 'time' in y.dtype.names: 

50 return [], {} 

51 # assemble data: 

52 data = [] 

53 for k in range(len(y['wave'])): 

54 eod = np.zeros((len(y['wave'][k]), 2)) 

55 eod[:, 0] = y['time'][k] 

56 eod[:, 1] = (y['wave'][k]).astype(float) 

57 data.append(eod) 

58 # assemble metadata: 

59 md = {} 

60 eod_md = [] 

61 for n in y.dtype.names: 

62 t = type(y[n][0]) 

63 if not t is np.ndarray: 

64 # some metadata may or may not differ between EODs: 

65 for k in range(len(y[n])): 

66 if y[n][k] and n != 'eodnum' and y[n][k] != y[n][0]: 

67 while len(eod_md) < len(y[n]): 

68 eod_md.append({}) 

69 for k in range(len(y[n])): 

70 v = y[n][k] 

71 if isinstance(v, str): 

72 v = v.replace('Date:', '') 

73 v = v.replace('Time:', '') 

74 v = v.replace('Time', '') 

75 v = v.strip() 

76 eod_md[k][n] = v 

77 break 

78 else: 

79 v = y[n][0] 

80 if isinstance(v, str): 

81 v = v.replace('Date:', '') 

82 v = v.replace('Time:', '') 

83 v = v.replace('Time', '') 

84 v = v.replace(' T: ', 'T') 

85 v = v.strip() 

86 md[n] = v 

87 for k in range(len(eod_md)): 

88 md[f'EOD{k}'] = eod_md[k] 

89 return data, md 

90 

91 

92def analyse_hopkins(pathes): 

93 """ Analyze the content of Hopkins files. 

94 

95 Prints out some statistics about the field names and types. 

96 

97 Parameters 

98 ---------- 

99 pathes: list of str 

100 Files to be analyzed. 

101 """ 

102 keys = {} 

103 types = {} 

104 data_types = {} 

105 for file_path in pathes: 

106 x = loadmat(file_path, squeeze_me=True) 

107 y = x['eod'].reshape(x['eod'].size) 

108 for n in y.dtype.names: 

109 c = keys.get(n, 0) 

110 keys[n] = c + 1 

111 t = type(y[n][0]) 

112 c = types.get(t, 0) 

113 types[t] = c + 1 

114 t = y['wave'][0].dtype 

115 c = data_types.get(t, 0) 

116 data_types[t] = c + 1 

117 

118 # each file contains several "wave" and "time" arrays for plotting the EODs. 

119 # within a file they might differ in size! 

120 

121 # print all keys found in the data with their frequency: 

122 print('keys:') 

123 for k in keys: 

124 print(f' {100*keys[k]/len(pathes):3.0f}%', k) 

125 print() 

126 

127 # print all wave data types with their frequency: 

128 print('data types:') 

129 for t in data_types: 

130 print(f' {data_types[t]:5d}', t) 

131 print() 

132 # 226 float64 

133 # 57 int16 

134 

135 # print types of all fields with their frequency: 

136 print('field types:') 

137 for t in types: 

138 print(f' {types[t]:5d}', t) 

139 print() 

140 # 2845 <class 'int'> 

141 # 4002 <class 'numpy.ndarray'> 

142 #14681 <class 'str'> 

143 # 1478 <class 'float'> 

144 

145 

146if __name__ == '__main__': 

147 

148 analyse_hopkins(sys.argv[1:]) 

149 

150 for file_path in sys.argv[1:]: 

151 print(file_path) 

152 data, md = load_hopkins(file_path) 

153 print_metadata(md, ' ') 

154 fig, ax = plt.subplots() 

155 ax.set_title(md.get('speciesIDweb', '')) 

156 for k in range(len(data)): 

157 ax.plot(1000*data[k][:, 0], data[k][:, 1]) 

158 ax.set_xlabel('Time [ms]') 

159 plt.show() 

160 print()