Expand source code
class SignalPlot:
def __init__(self, data, samplingrate, unit, filename, channel, verbose, cfg):
self.filename = filename
self.channel = channel
self.rate = samplingrate
self.data = data
self.unit = unit
self.cfg = cfg
self.verbose = verbose
self.tmax = (len(self.data)-1)/self.rate
self.toffset = 0.0
self.twindow = 8.0
if self.twindow > self.tmax:
self.twindow = np.round(2 ** (np.floor(np.log(self.tmax) / np.log(2.0)) + 1.0))
self.ymin = -1.0
self.ymax = +1.0
self.trace_artist = None
self.spectrogram_artist = None
self.fmin = 0.0
self.fmax = 0.0
self.decibel = True
self.freq_resolution = self.cfg.value('frequencyResolution')
self.deltaf = 1.0
self.mains_freq = self.cfg.value('mainsFreq')
self.power_label = None
self.all_peaks_artis = None
self.good_peaks_artist = None
self.power_artist = None
self.power_frequency_label = None
self.peak_artists = []
self.legend = True
self.legendhandle = None
self.help = False
self.helptext = []
self.allpeaks = []
self.fishlist = []
self.mains = []
self.peak_specmarker = []
self.peak_annotation = []
self.min_clip = self.cfg.value('minClipAmplitude')
self.max_clip = self.cfg.value('maxClipAmplitude')
self.colorrange, self.markerrange = colors_markers()
# audio output:
self.audio = PlayAudio()
# set key bindings:
plt.rcParams['keymap.fullscreen'] = 'ctrl+f'
plt.rcParams['keymap.pan'] = 'ctrl+m'
plt.rcParams['keymap.quit'] = 'ctrl+w, alt+q, q'
plt.rcParams['keymap.yscale'] = ''
plt.rcParams['keymap.xscale'] = ''
plt.rcParams['keymap.grid'] = ''
#plt.rcParams['keymap.all_axes'] = ''
# the figure:
plt.ioff()
self.fig = plt.figure(figsize=(15, 9))
self.fig.canvas.manager.set_window_title(self.filename + ' channel {0:d}'.format(self.channel))
self.fig.canvas.mpl_connect('key_press_event', self.keypress)
self.fig.canvas.mpl_connect('button_press_event', self.buttonpress)
self.fig.canvas.mpl_connect('pick_event', self.onpick)
self.fig.canvas.mpl_connect('resize_event', self.resize)
# trace plot:
self.axt = self.fig.add_axes([0.1, 0.7, 0.87, 0.25])
self.axt.set_ylabel('Amplitude [{:s}]'.format(self.unit))
ht = self.axt.text(0.98, 0.05, '(ctrl+) page and arrow up, down, home, end: scroll', ha='right',
transform=self.axt.transAxes)
self.helptext.append(ht)
ht = self.axt.text(0.98, 0.15, '+, -, X, x: zoom in/out', ha='right', transform=self.axt.transAxes)
self.helptext.append(ht)
ht = self.axt.text(0.98, 0.25, 'y,Y,v,V: zoom amplitudes', ha='right', transform=self.axt.transAxes)
self.helptext.append(ht)
ht = self.axt.text(0.98, 0.35, 'p,P: play audio (display,all)', ha='right', transform=self.axt.transAxes)
self.helptext.append(ht)
ht = self.axt.text(0.98, 0.45, 'ctrl-f: full screen', ha='right', transform=self.axt.transAxes)
self.helptext.append(ht)
ht = self.axt.text(0.98, 0.55, 'w: plot waveform into png file', ha='right', transform=self.axt.transAxes)
self.helptext.append(ht)
ht = self.axt.text(0.98, 0.65, 's: save figure', ha='right', transform=self.axt.transAxes)
self.helptext.append(ht)
ht = self.axt.text(0.98, 0.75, 'S: save audiosegment', ha='right', transform=self.axt.transAxes)
self.helptext.append(ht)
ht = self.axt.text(0.98, 0.85, 'q: quit', ha='right', transform=self.axt.transAxes)
self.helptext.append(ht)
ht = self.axt.text(0.98, 0.95, 'h: toggle this help', ha='right', transform=self.axt.transAxes)
self.helptext.append(ht)
self.axt.set_xticklabels([])
# spectrogram:
self.axs = self.fig.add_axes([0.1, 0.45, 0.87, 0.25])
self.axs.set_xlabel('Time [seconds]')
self.axs.set_ylabel('Frequency [Hz]')
# power spectrum:
self.axp = self.fig.add_axes([0.1, 0.1, 0.87, 0.25])
ht = self.axp.text(0.98, 0.9, 'r, R: frequency resolution', ha='right', transform=self.axp.transAxes)
self.helptext.append(ht)
ht = self.axp.text(0.98, 0.8, 'f, F: zoom', ha='right', transform=self.axp.transAxes)
self.helptext.append(ht)
ht = self.axp.text(0.98, 0.7, '(ctrl+) left, right: move', ha='right', transform=self.axp.transAxes)
self.helptext.append(ht)
ht = self.axp.text(0.98, 0.6, 'l: toggle legend', ha='right', transform=self.axp.transAxes)
self.helptext.append(ht)
ht = self.axp.text(0.98, 0.5, 'd: toggle decibel', ha='right', transform=self.axp.transAxes)
self.helptext.append(ht)
ht = self.axp.text(0.98, 0.4, 'm: toggle mains filter', ha='right', transform=self.axp.transAxes)
self.helptext.append(ht)
ht = self.axp.text(0.98, 0.3, 'left mouse: show peak properties', ha='right', transform=self.axp.transAxes)
self.helptext.append(ht)
ht = self.axp.text(0.98, 0.2, 'shift/ctrl + left/right mouse: goto previous/next harmonic', ha='right',
transform=self.axp.transAxes)
self.helptext.append(ht)
# plot:
for ht in self.helptext:
ht.set_visible(self.help)
self.update_plots(False)
plt.show()
def __del__(self):
self.audio.close()
def remove_peak_annotation(self):
for fm in self.peak_specmarker:
fm.remove()
self.peak_specmarker = []
for fa in self.peak_annotation:
fa.remove()
self.peak_annotation = []
def annotate_peak(self, peak, harmonics=-1, inx=-1):
# marker:
if inx >= 0:
m, = self.axs.plot([self.toffset + 0.01 * self.twindow], [peak[0]], linestyle='None',
color=self.colorrange[inx % len(self.colorrange)],
marker=self.markerrange[inx], ms=10.0, mec=None, mew=0.0, zorder=2)
else:
m, = self.axs.plot([self.toffset + 0.01 * self.twindow], [peak[0]], linestyle='None',
color='k', marker='o', ms=10.0, mec=None, mew=0.0, zorder=2)
self.peak_specmarker.append(m)
# annotation:
fwidth = self.fmax - self.fmin
pl = []
pl.append(r'$f=$%.1f Hz' % peak[0])
pl.append(r'$h=$%d' % harmonics)
pl.append(r'$p=$%g' % peak[1])
pl.append(r'$c=$%.0f' % peak[2])
self.peak_annotation.append(self.axp.annotate('\n'.join(pl), xy=(peak[0], peak[1]),
xytext=(peak[0] + 0.03 * fwidth, peak[1]),
bbox=dict(boxstyle='round', facecolor='white'),
arrowprops=dict(arrowstyle='-')))
def annotate_fish(self, fish, inx=-1):
self.remove_peak_annotation()
for harmonic, freq in enumerate(fish[:, 0]):
peak = self.allpeaks[np.abs(self.allpeaks[:, 0] - freq) < 0.8 * self.deltaf, :]
if len(peak) > 0:
self.annotate_peak(peak[0, :], harmonic, inx)
self.fig.canvas.draw()
def update_plots(self, draw=True):
self.remove_peak_annotation()
# trace:
self.axt.set_xlim(self.toffset, self.toffset + self.twindow)
t0 = int(np.round(self.toffset * self.rate))
t1 = int(np.round((self.toffset + self.twindow) * self.rate))
if t1>len(self.data):
t1 = len(self.data)
time = np.arange(t0, t1) / self.rate
if self.trace_artist == None:
self.trace_artist, = self.axt.plot(time, self.data[t0:t1,self.channel])
else:
self.trace_artist.set_data(time, self.data[t0:t1,self.channel])
self.axt.set_ylim(self.ymin, self.ymax)
# compute power spectrum:
n_fft = nfft(self.rate, self.freq_resolution)
t00 = t0
t11 = t1
w = t11 - t00
minw = n_fft * (self.cfg.value('minPSDAverages') + 1) // 2
if t11 - t00 < minw:
w = minw
t11 = t00 + w
if t11 >= len(self.data):
t11 = len(self.data)
t00 = t11 - w
if t00 < 0:
t00 = 0
t11 = w
freqs, power = psd(self.data[t00:t11,self.channel], self.rate,
self.freq_resolution, detrend=ml.detrend_mean)
self.deltaf = freqs[1] - freqs[0]
# detect fish:
h_kwargs = psd_peak_detection_args(self.cfg)
h_kwargs.update(harmonic_groups_args(self.cfg))
self.fishlist, fzero_harmonics, self.mains, self.allpeaks, peaks, lowth, highth, center = harmonic_groups(freqs, power, verbose=self.verbose, **h_kwargs)
highth = center + highth - 0.5 * lowth
lowth = center + 0.5 * lowth
# spectrogram:
t2 = t1 + n_fft
freqs, bins, specpower = spectrogram(self.data[t0:t2,self.channel],
self.rate,
self.freq_resolution,
detrend=ml.detrend_mean)
z = decibel(specpower)
z = np.flipud(z)
extent = self.toffset, self.toffset + np.amax(bins), freqs[0], freqs[-1]
self.axs.set_xlim(self.toffset, self.toffset + self.twindow)
if self.spectrogram_artist == None:
self.fmax = np.round((freqs[-1] / 4.0) / 100.0) * 100.0
min = highth
min = np.percentile(z, 70.0)
max = np.percentile(z, 99.9) + 30.0
# cm = plt.get_cmap( 'hot_r' )
cm = plt.get_cmap('jet')
self.spectrogram_artist = self.axs.imshow(z, aspect='auto',
extent=extent, vmin=min, vmax=max,
cmap=cm, zorder=1)
else:
self.spectrogram_artist.set_data(z)
self.spectrogram_artist.set_extent(extent)
self.axs.set_ylim(self.fmin, self.fmax)
# power spectrum:
self.axp.set_xlim(self.fmin, self.fmax)
if self.deltaf >= 1000.0:
dfs = '%.3gkHz' % 0.001 * self.deltaf
else:
dfs = '%.3gHz' % self.deltaf
tw = float(w) / self.rate
if tw < 1.0:
tws = '%.3gms' % (1000.0 * tw)
else:
tws = '%.3gs' % (tw)
a = 2 * w // n_fft - 1 # number of ffts
m = ''
if self.cfg.value('mainsFreq') > 0.0:
m = ', mains=%.0fHz' % self.cfg.value('mainsFreq')
if self.power_frequency_label == None:
self.power_frequency_label = self.axp.set_xlabel(
r'Frequency [Hz] (nfft={:d}, $\Delta f$={:s}: T={:s}/{:d}{:s})'.format(n_fft, dfs, tws, a, m))
else:
self.power_frequency_label.set_text(
r'Frequency [Hz] (nfft={:d}, $\Delta f$={:s}: T={:s}/{:d}{:s})'.format(n_fft, dfs, tws, a, m))
self.axp.set_xlim(self.fmin, self.fmax)
if self.power_label == None:
self.power_label = self.axp.set_ylabel('Power')
if self.decibel:
if len(self.allpeaks) > 0:
self.allpeaks[:, 1] = decibel(self.allpeaks[:, 1])
power = decibel(power)
pmin = np.min(power[freqs < self.fmax])
pmin = np.floor(pmin / 10.0) * 10.0
pmax = np.max(power[freqs < self.fmax])
pmax = np.ceil(pmax / 10.0) * 10.0
doty = pmax - 5.0
self.power_label.set_text('Power [dB]')
self.axp.set_ylim(pmin, pmax)
else:
pmax = np.max(power[freqs < self.fmax])
doty = pmax
pmax *= 1.1
self.power_label.set_text('Power')
self.axp.set_ylim(0.0, pmax)
if self.all_peaks_artis == None:
self.all_peaks_artis, = self.axp.plot(self.allpeaks[:, 0],
np.zeros(len(self.allpeaks[:, 0])) + doty,
'o', color='#ffffff')
self.good_peaks_artist, = self.axp.plot(peaks, np.zeros(len(peaks)) + doty,
'o', color='#888888')
else:
self.all_peaks_artis.set_data(self.allpeaks[:, 0],
np.zeros(len(self.allpeaks[:, 0])) + doty)
self.good_peaks_artist.set_data(peaks, np.zeros(len(peaks)) + doty)
labels = []
fsizes = [np.sqrt(np.sum(self.fishlist[k][:, 1])) for k in range(len(self.fishlist))]
fmaxsize = np.max(fsizes) if len(fsizes) > 0 else 1.0
for k in range(len(self.peak_artists)):
self.peak_artists[k].remove()
self.peak_artists = []
for k in range(len(self.fishlist)):
if k >= len(self.markerrange):
break
fpeaks = self.fishlist[k][:, 0]
fpeakinx = [int(np.round(fp / self.deltaf)) for fp in fpeaks if fp < freqs[-1]]
fsize = 7.0 + 10.0 * (fsizes[k] / fmaxsize) ** 0.5
fishpoints, = self.axp.plot(fpeaks[:len(fpeakinx)], power[fpeakinx], linestyle='None',
color=self.colorrange[k % len(self.colorrange)],
marker=self.markerrange[k], ms=fsize,
mec=None, mew=0.0, zorder=1)
self.peak_artists.append(fishpoints)
if self.deltaf < 0.1:
labels.append('%4.2f Hz' % fpeaks[0])
elif self.deltaf < 1.0:
labels.append('%4.1f Hz' % fpeaks[0])
else:
labels.append('%4.0f Hz' % fpeaks[0])
if len(self.mains) > 0:
fpeaks = self.mains[:, 0]
fpeakinx = np.array([np.round(fp / self.deltaf) for fp in fpeaks if fp < freqs[-1]], dtype=int)
fishpoints, = self.axp.plot(fpeaks[:len(fpeakinx)],
power[fpeakinx], linestyle='None',
marker='.', color='k', ms=10, mec=None, mew=0.0, zorder=2)
self.peak_artists.append(fishpoints)
labels.append('%3.0f Hz mains' % self.cfg.value('mainsFreq'))
ncol = (len(labels)-1) // 8 + 1
self.legendhandle = self.axs.legend(self.peak_artists[:len(labels)], labels, loc='upper right', ncol=ncol)
self.legenddict = dict()
for legpoints, (finx, fish) in zip(self.legendhandle.get_lines(), enumerate(self.fishlist)):
legpoints.set_picker(8)
self.legenddict[legpoints] = [finx, fish]
self.legendhandle.set_visible(self.legend)
if self.power_artist == None:
self.power_artist, = self.axp.plot(freqs, power, 'b', zorder=3)
else:
self.power_artist.set_data(freqs, power)
if draw:
self.fig.canvas.draw()
def keypress(self, event):
# print('pressed', event.key)
if event.key in '+=X':
if self.twindow * self.rate > 20:
self.twindow *= 0.5
self.update_plots()
elif event.key in '-x':
if self.twindow < len(self.data) / self.rate:
self.twindow *= 2.0
self.update_plots()
elif event.key == 'pagedown':
if self.toffset + 0.5 * self.twindow < len(self.data) / self.rate:
self.toffset += 0.5 * self.twindow
self.update_plots()
elif event.key == 'pageup':
if self.toffset > 0:
self.toffset -= 0.5 * self.twindow
if self.toffset < 0.0:
self.toffset = 0.0
self.update_plots()
elif event.key == 'a':
if self.min_clip == 0.0 or self.max_clip == 0.0:
self.min_clip, self.max_clip = clip_amplitudes(
self.data[:,self.channel],
**clip_args(self.cfg, self.rate))
try:
if self.cfg.value('windowSize') <= 0.0:
self.cfg.set('windowSize', (len(self.data)-1)/self.rate)
idx0, idx1, clipped = best_window_indices(
self.data[:,self.channel], self.rate,
min_clip=self.min_clip, max_clip=self.max_clip,
**best_window_args(self.cfg))
if idx1 > 0:
self.toffset = idx0 / self.rate
self.twindow = (idx1 - idx0) / self.rate
self.twindow *= 2.0/(self.cfg.value('numberPSDWindows')+1.0)
self.update_plots()
except UserWarning as e:
if self.verbose > 0:
print(str(e))
elif event.key == 'ctrl+pagedown':
if self.toffset + 5.0 * self.twindow < len(self.data) / self.rate:
self.toffset += 5.0 * self.twindow
self.update_plots()
elif event.key == 'ctrl+pageup':
if self.toffset > 0:
self.toffset -= 5.0 * self.twindow
if self.toffset < 0.0:
self.toffset = 0.0
self.update_plots()
elif event.key == 'down':
if self.toffset + self.twindow < len(self.data) / self.rate:
self.toffset += 0.05 * self.twindow
self.update_plots()
elif event.key == 'up':
if self.toffset > 0.0:
self.toffset -= 0.05 * self.twindow
if self.toffset < 0.0:
self.toffset = 0.0
self.update_plots()
elif event.key == 'home':
if self.toffset > 0.0:
self.toffset = 0.0
self.update_plots()
elif event.key == 'end':
toffs = np.floor(len(self.data) / self.rate / self.twindow) * self.twindow
if self.toffset < toffs:
self.toffset = toffs
self.update_plots()
elif event.key == 'y':
h = self.ymax - self.ymin
c = 0.5 * (self.ymax + self.ymin)
self.ymin = c - h
self.ymax = c + h
self.axt.set_ylim(self.ymin, self.ymax)
self.fig.canvas.draw()
elif event.key == 'Y':
h = 0.25 * (self.ymax - self.ymin)
c = 0.5 * (self.ymax + self.ymin)
self.ymin = c - h
self.ymax = c + h
self.axt.set_ylim(self.ymin, self.ymax)
self.fig.canvas.draw()
elif event.key == 'v':
t0 = int(np.round(self.toffset * self.rate))
t1 = int(np.round((self.toffset + self.twindow) * self.rate))
min = np.min(self.data[t0:t1,self.channel])
max = np.max(self.data[t0:t1,self.channel])
h = 0.5 * (max - min)
c = 0.5 * (max + min)
self.ymin = c - h
self.ymax = c + h
self.axt.set_ylim(self.ymin, self.ymax)
self.fig.canvas.draw()
elif event.key == 'V':
self.ymin = -1.0
self.ymax = +1.0
self.axt.set_ylim(self.ymin, self.ymax)
self.fig.canvas.draw()
elif event.key == 'left':
if self.fmin > 0.0:
fwidth = self.fmax - self.fmin
self.fmin -= 0.5 * fwidth
self.fmax -= 0.5 * fwidth
if self.fmin < 0.0:
self.fmin = 0.0
self.fmax = fwidth
self.axs.set_ylim(self.fmin, self.fmax)
self.axp.set_xlim(self.fmin, self.fmax)
self.fig.canvas.draw()
elif event.key == 'right':
if self.fmax < 0.5 * self.rate:
fwidth = self.fmax - self.fmin
self.fmin += 0.5 * fwidth
self.fmax += 0.5 * fwidth
self.axs.set_ylim(self.fmin, self.fmax)
self.axp.set_xlim(self.fmin, self.fmax)
self.fig.canvas.draw()
elif event.key == 'ctrl+left':
if self.fmin > 0.0:
fwidth = self.fmax - self.fmin
self.fmin = 0.0
self.fmax = fwidth
self.axs.set_ylim(self.fmin, self.fmax)
self.axp.set_xlim(self.fmin, self.fmax)
self.fig.canvas.draw()
elif event.key == 'ctrl+right':
if self.fmax < 0.5 * self.rate:
fwidth = self.fmax - self.fmin
fm = 0.5 * self.rate
self.fmax = np.ceil(fm / fwidth) * fwidth
self.fmin = self.fmax - fwidth
if self.fmin < 0.0:
self.fmin = 0.0
self.fmax = fwidth
self.axs.set_ylim(self.fmin, self.fmax)
self.axp.set_xlim(self.fmin, self.fmax)
self.fig.canvas.draw()
elif event.key in 'f':
if self.fmax < 0.5 * self.rate or self.fmin > 0.0:
fwidth = self.fmax - self.fmin
if self.fmax < 0.5 * self.rate:
self.fmax = self.fmin + 2.0 * fwidth
elif self.fmin > 0.0:
self.fmin = self.fmax - 2.0 * fwidth
if self.fmin < 0.0:
self.fmin = 0.0
self.fmax = 2.0 * fwidth
self.axs.set_ylim(self.fmin, self.fmax)
self.axp.set_xlim(self.fmin, self.fmax)
self.fig.canvas.draw()
elif event.key in 'F':
if self.fmax - self.fmin > 1.0:
fwidth = self.fmax - self.fmin
self.fmax = self.fmin + 0.5 * fwidth
self.axs.set_ylim(self.fmin, self.fmax)
self.axp.set_xlim(self.fmin, self.fmax)
self.fig.canvas.draw()
elif event.key in 'r':
if self.freq_resolution < 1000.0:
self.freq_resolution *= 2.0
self.update_plots()
elif event.key in 'R':
if 1.0 / self.freq_resolution < self.tmax:
self.freq_resolution *= 0.5
self.update_plots()
elif event.key in 'd':
self.decibel = not self.decibel
self.update_plots()
elif event.key in 'm':
if self.cfg.value('mainsFreq') == 0.0:
self.cfg.set('mainsFreq', self.mains_freq)
else:
self.cfg.set('mainsFreq', 0.0)
self.update_plots()
elif event.key in 't':
t_diff = self.cfg.value('highThresholdFactor') - self.cfg.value('lowThresholdFactor')
self.cfg.set('lowThresholdFactor', self.cfg.value('lowThresholdFactor') - 0.1)
if self.cfg.value('lowThresholdFactor') < 0.1:
self.cfg.set('lowThresholdFactor', 0.1)
self.cfg.set('highThresholdFactor', self.cfg.value('lowThresholdFactor') + t_diff)
print('lowThresholdFactor =', self.cfg.value('lowThresholdFactor'))
self.update_plots()
elif event.key in 'T':
t_diff = self.cfg.value('highThresholdFactor') - self.cfg.value('lowThresholdFactor')
self.cfg.set('lowThresholdFactor', self.cfg.value('lowThresholdFactor') + 0.1)
if self.cfg.value('lowThresholdFactor') > 20.0:
self.cfg.set('lowThresholdFactor', 20.0)
self.cfg.set('highThresholdFactor', self.cfg.value('lowThresholdFactor') + t_diff)
print('lowThresholdFactor =', self.cfg.value('lowThresholdFactor'))
self.update_plots()
elif event.key == 'escape':
self.remove_peak_annotation()
self.fig.canvas.draw()
elif event.key in 'h':
self.help = not self.help
for ht in self.helptext:
ht.set_visible(self.help)
self.fig.canvas.draw()
elif event.key in 'l':
self.legend = not self.legend
self.legendhandle.set_visible(self.legend)
self.fig.canvas.draw()
elif event.key in 'w':
self.plot_waveform()
elif event.key in 'p':
self.play_segment()
elif event.key in 'P':
self.play_all()
elif event.key in '1' :
self.play_tone('c3')
elif event.key in '2' :
self.play_tone('a3')
elif event.key in '3' :
self.play_tone('e4')
elif event.key in '4' :
self.play_tone('a4')
elif event.key in '5' :
self.play_tone('c5')
elif event.key in '6' :
self.play_tone('e5')
elif event.key in '7' :
self.play_tone('g5')
elif event.key in '8' :
self.play_tone('a5')
elif event.key in '9' :
self.play_tone('c6')
elif event.key in 'S':
self.save_segment()
def buttonpress( self, event ) :
# print('mouse pressed', event.button, event.key, event.step)
if event.inaxes == self.axp:
if event.key == 'shift' or event.key == 'control':
# show next or previous harmonic:
if event.key == 'shift':
if event.button == 1:
ftarget = event.xdata / 2.0
elif event.button == 3:
ftarget = event.xdata * 2.0
else:
if event.button == 1:
ftarget = event.xdata / 1.5
elif event.button == 3:
ftarget = event.xdata * 1.5
foffs = event.xdata - self.fmin
fwidth = self.fmax - self.fmin
self.fmin = ftarget - foffs
self.fmax = self.fmin + fwidth
self.axs.set_ylim(self.fmin, self.fmax)
self.axp.set_xlim(self.fmin, self.fmax)
self.fig.canvas.draw()
else:
# put label on peak
self.remove_peak_annotation()
# find closest peak:
fwidth = self.fmax - self.fmin
peakdist = np.abs(self.allpeaks[:, 0] - event.xdata)
inx = np.argmin(peakdist)
if peakdist[inx] < 0.005 * fwidth:
peak = self.allpeaks[inx, :]
# find fish:
foundfish = False
for finx, fish in enumerate(self.fishlist):
if np.min(np.abs(fish[:, 0] - peak[0])) < 0.8 * self.deltaf:
self.annotate_fish(fish, finx)
foundfish = True
break
if not foundfish:
self.annotate_peak(peak)
self.fig.canvas.draw()
else:
self.fig.canvas.draw()
def onpick(self, event):
# print('pick')
legendpoint = event.artist
finx, fish = self.legenddict[legendpoint]
self.annotate_fish(fish, finx)
def resize(self, event):
# print('resized', event.width, event.height)
leftpixel = 80.0
rightpixel = 20.0
xaxispixel = 50.0
toppixel = 20.0
timeaxis = 0.42
left = leftpixel / event.width
width = 1.0 - left - rightpixel / event.width
xaxis = xaxispixel / event.height
top = toppixel / event.height
height = (1.0 - timeaxis - top) / 2.0
if left < 0.5 and width < 1.0 and xaxis < 0.3 and top < 0.2:
self.axt.set_position([left, timeaxis + height, width, height])
self.axs.set_position([left, timeaxis, width, height])
self.axp.set_position([left, xaxis, width, timeaxis - 2.0 * xaxis])
def plot_waveform(self):
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
name = self.filename.split('.')[0]
if self.channel > 0:
ax.set_title('{filename} channel={channel:d}'.format(
filename=self.filename, channel=self.channel))
figfile = '{name}-{channel:d}-{time:.4g}s-waveform.png'.format(
name=name, channel=self.channel, time=self.toffset)
else:
ax.set_title(self.filename)
figfile = '{name}-{time:.4g}s-waveform.png'.format(
name=name, time=self.toffset)
t0 = int(np.round(self.toffset * self.rate))
t1 = int(np.round((self.toffset + self.twindow) * self.rate))
if t1>len(self.data):
t1 = len(self.data)
time = np.arange(t0, t1) / self.rate
if self.twindow < 1.0:
ax.set_xlabel('Time [ms]')
ax.set_xlim(1000.0 * self.toffset,
1000.0 * (self.toffset + self.twindow))
ax.plot(1000.0 * time, self.data[t0:t1,self.channel])
else:
ax.set_xlabel('Time [s]')
ax.set_xlim(self.toffset, self.toffset + self.twindow)
ax.plot(time, self.data[t0:t1,self.channel])
ax.set_ylabel('Amplitude [{:s}]'.format(self.unit))
fig.tight_layout()
fig.savefig(figfile)
fig.clear()
plt.close(fig)
print('saved waveform figure to', figfile)
def play_segment(self):
t0 = int(np.round(self.toffset * self.rate))
t1 = int(np.round((self.toffset + self.twindow) * self.rate))
playdata = 1.0 * self.data[t0:t1,self.channel]
fade(playdata, self.rate, 0.1)
self.audio.play(playdata, self.rate, blocking=False)
def save_segment(self):
t0s = int(np.round(self.toffset))
t1s = int(np.round(self.toffset + self.twindow))
t0 = int(np.round(self.toffset * self.rate))
t1 = int(np.round((self.toffset + self.twindow) * self.rate))
savedata = 1.0 * self.data[t0:t1,self.channel]
filename = self.filename.split('.')[0]
segmentfilename = '{name}-{time0:.4g}s-{time1:.4g}s.wav'.format(
name=filename, time0=t0s, time1 = t1s)
write_audio(segmentfilename, savedata, self.data.rate)
print('saved segment to: ' , segmentfilename)
def play_all(self):
self.audio.play(self.data[:,self.channel], self.rate,
blocking=False)
def play_tone( self, frequency ) :
self.audio.beep(1.0, frequency)