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

1""" 

2Compare fishlists created by the harmonics module in order to create a fishlist with 

3fishes present in all fishlists. 

4 

5- `consistent_fishes()`: Compares a list of fishlists and builds a consistent fishlist. 

6- `plot_consistent_fishes()`: Visualize the algorithm of consisten_fishes(). 

7""" 

8 

9import numpy as np 

10from .harmonics import fundamental_freqs 

11 

12 

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) 

17 

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. 

29 

30 

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. 

40 

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) 

49 

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 

54 

55 index = np.arange(len(fundamentals[0]))[consistency_help == len(fundamentals)] 

56 consistent_fundamentals = fundamentals[0][index] 

57 

58 return consistent_fundamentals, index 

59 

60 

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. 

64 

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. 

67 

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. 

83 

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)) 

93 

94 fundamentals = fundamental_freqs(fishlists) 

95 if len(fundamentals) == 0: 

96 return [] 

97 

98 consistent_fundamentals, index = find_consistency(fundamentals) 

99 

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]) 

104 

105 if plot_data_func: 

106 plot_data_func(fishlists, filtered_fishlist, **kwargs) 

107 

108 return filtered_fishlist 

109 

110 

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. 

114 

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) 

132 

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) 

143 

144 

145if __name__ == '__main__': 

146 import matplotlib.pyplot as plt 

147 

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('') 

155 

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 # 

164 

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() 

168 

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) 

173 

174 # check empty fishlist: 

175 fishlists = [[], []] 

176 filtered_fishlist = consistent_fishes(fishlists, verbose=1) 

177 print(filtered_fishlist) 

178 

179 # check really empty fishlist: 

180 fishlists = [] 

181 filtered_fishlist = consistent_fishes(fishlists, verbose=1) 

182 print(filtered_fishlist) 

183