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
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-15 17:50 +0000
1"""Load EODs from Hopkins files.
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.
7## Functions
9- `load_hopkins()`: load a Hopkins file containing a few EOD pulses.
10- `analyse_hopkins()`: analyze the content of Hopkins files.
12"""
14import sys
15import numpy as np
16import matplotlib.pyplot as plt
18from scipy.io import loadmat
19from audioio import print_metadata
22def load_hopkins(file_path):
23 """ Load a Hopkins file containing a few EOD pulses.
25 Parameters
26 ----------
27 file_path: str
28 The mat file with the data.
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.
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
92def analyse_hopkins(pathes):
93 """ Analyze the content of Hopkins files.
95 Prints out some statistics about the field names and types.
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
118 # each file contains several "wave" and "time" arrays for plotting the EODs.
119 # within a file they might differ in size!
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()
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
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'>
146if __name__ == '__main__':
148 analyse_hopkins(sys.argv[1:])
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()