Coverage for src/thunderfish/consistentfishes.py: 0%
59 statements
« prev ^ index » next coverage.py v7.5.0, created at 2024-04-29 16:21 +0000
« prev ^ index » next coverage.py v7.5.0, created at 2024-04-29 16:21 +0000
1"""
2Compare fishlists created by the harmonics module in order to create a fishlist with
3fishes present in all fishlists.
5- `consistent_fishes()`: Compares a list of fishlists and builds a consistent fishlist.
6- `plot_consistent_fishes()`: Visualize the algorithm of consisten_fishes().
7"""
9import numpy as np
10from .harmonics import fundamental_freqs
13def find_consistency(fundamentals, df_th=1.0):
14 """
15 Compares lists of floats to find these values consistent in every list.
16 (with a certain threshold)
18 Every value of the first list is compared to the values of the other
19 lists. The consistency_help array consists in the beginning of ones,
20 has the same length as the first list and is used to keep the
21 information about values that are available in several lists. If the
22 difference between a value of the first list and a value of another
23 list is below the threshold the entry of the consistency_help array
24 is added 1 to at the index of the value in the value in the first
25 list. The indices of the consistency_help array that are equal to
26 the amount of lists compared are the indices of the values of the
27 first list that are consistent in all lists. The consistent value
28 array and the indices are returned.
31 Parameters
32 ----------
33 fundamentals: 2-D array
34 List of lists containing the fundamentals of a fishlist.
35 fundamentals = [ [f1, f1, ..., f1, f1], [f2, f2, ..., f2, f2], ..., [fn, fn, ..., fn, fn] ]
36 df_th: float
37 Frequency threshold for the comparison of different fishlists in Hertz. If the fundamental
38 frequencies of two fishes from different fishlists vary less than this threshold they are
39 assigned as the same fish.
41 Returns
42 -------
43 consistent_fundamentals: 1-D array
44 List containing all values that are available in all given lists.
45 index: 1-D array
46 Indices of the values that are in every list relating to the fist list in fishlists.
47 """
48 consistency_help = np.ones(len(fundamentals[0]), dtype=int)
50 for enu, fundamental in enumerate(fundamentals[0]):
51 for list in range(1, len(fundamentals)):
52 if np.sum(np.abs(fundamentals[list] - fundamental) < df_th) > 0:
53 consistency_help[enu] += 1
55 index = np.arange(len(fundamentals[0]))[consistency_help == len(fundamentals)]
56 consistent_fundamentals = fundamentals[0][index]
58 return consistent_fundamentals, index
61def consistent_fishes(fishlists, verbose=0, plot_data_func=None, df_th=1.0, **kwargs):
62 """
63 Compares several fishlists to create a fishlist only containing these fishes present in all these fishlists.
65 Therefore several functions are used to first extract the fundamental frequencies of every fish in each fishlist,
66 before comparing them and building a fishlist only containing these fishes present in all fishlists.
68 Parameters
69 ----------
70 fishlists: list of list of 2D array
71 List of fishlists with harmonics and each frequency and power.
72 fishlists[fishlist][fish][harmonic][frequency, power]
73 plot_data_func:
74 Function that visualizes what consistent_fishes() did.
75 verbose: int
76 When the value larger than one you get additional shell output.
77 df_th: float
78 Frequency threshold for the comparison of different fishlists in Hertz. If the fundamental
79 frequencies of two fishes from different fishlists vary less than this threshold they are
80 assigned as the same fish.
81 **kwargs: dict
82 Passed on to plot function.
84 Returns
85 -------
86 filtered_fishlist: list of 2-D arrays
87 New fishlist with the same structure as a fishlist in fishlists only
88 containing these fishes that are available in every fishlist in fishlists.
89 fishlist[fish][harmonic][frequency, power]
90 """
91 if verbose >= 1:
92 print('Finding consistent fishes out of %d fishlists ...' % len(fishlists))
94 fundamentals = fundamental_freqs(fishlists)
95 if len(fundamentals) == 0:
96 return []
98 consistent_fundamentals, index = find_consistency(fundamentals)
100 # creates a filtered fishlist only containing the data of the fishes consistent in several fishlists.
101 filtered_fishlist = []
102 for idx in index:
103 filtered_fishlist.append(fishlists[0][idx])
105 if plot_data_func:
106 plot_data_func(fishlists, filtered_fishlist, **kwargs)
108 return filtered_fishlist
111def plot_consistent_fishes(fishlists, filtered_fishlist, ax, fs):
112 """
113 Creates an axis for plotting all lists and the consistent values marked with a bar.
115 Parameters
116 ----------
117 filtered_fishlist: 3-D array
118 Contains power and frequency of these fishes that hve been detected in
119 several powerspectra using different resolutions.
120 fishlists: 4-D array or 3-D array
121 List of or single fishlists with harmonics and each frequency and power.
122 fishlists[fishlist][fish][harmonic][frequency, power]
123 fishlists[fish][harmonic][frequency, power]
124 ax: axis for plot
125 Empty axis that is filled with content in the function.
126 fs: int
127 Fontsize for the plot.
128 """
129 for list in np.arange(len(fishlists)):
130 for fish in np.arange(len(fishlists[list])):
131 ax.plot(list + 1, fishlists[list][fish][0][0], 'k.', markersize=10)
133 for fish in np.arange(len(filtered_fishlist)):
134 x = np.arange(len(fishlists)) + 1
135 y = [filtered_fishlist[fish][0][0] for i in range(len(fishlists))]
136 if fish == 0:
137 ax.plot(x, y, '-r', linewidth=10, alpha=0.5, label='consistent in all lists')
138 else:
139 ax.plot(x, y, '-r', linewidth=10, alpha=0.5)
140 ax.set_xlim([0, len(fishlists) + 1])
141 ax.set_ylabel('value', fontsize=fs)
142 ax.set_xlabel('list no.', fontsize=fs)
145if __name__ == '__main__':
146 import matplotlib.pyplot as plt
148 print('Creating one fishlist containing only the fishes that are consistant in several fishlists.')
149 print('The input structure looks like this:')
150 print(' fishlists[list][fish][harmonic][frequency, power]')
151 print('')
152 print('Usage:')
153 print(' python -m thunderfish.consistentfishes')
154 print('')
156 # example 4-D array containing of 4 fishlists all haveing 3 fishes with 1 harmonic with frequency and power
157 fishlists = [[np.array([np.array([350, 0])]), np.array([np.array([700.2, 0])]), np.array([np.array([1050, 0])])],
158 [np.array([np.array([350.1, 0])]), np.array([np.array([699.8, 0])]), np.array([np.array([250.2, 0])])],
159 [np.array([np.array([349.7, 0])]), np.array([np.array([700.4, 0])]),
160 np.array([np.array([1050.2, 0])])],
161 [np.array([np.array([349.8, 0])]), np.array([np.array([700.5, 0])]),
162 np.array([np.array([1050.3, 0])])]]
163 #
165 fig, ax = plt.subplots()
166 filtered_fishlist = consistent_fishes(fishlists, verbose=1, plot_data_func=plot_consistent_fishes, ax=ax, fs=12)
167 plt.show()
169 # check almost empty fishlist:
170 fishlists = [[], [np.array([[349.8, 0], [700.5, 0], [1050.3, 0]])], []]
171 filtered_fishlist = consistent_fishes(fishlists, verbose=1)
172 print(filtered_fishlist)
174 # check empty fishlist:
175 fishlists = [[], []]
176 filtered_fishlist = consistent_fishes(fishlists, verbose=1)
177 print(filtered_fishlist)
179 # check really empty fishlist:
180 fishlists = []
181 filtered_fishlist = consistent_fishes(fishlists, verbose=1)
182 print(filtered_fishlist)