diff --git a/figures/SNR_distrib.pdf b/figures/SNR_distrib.pdf index 2cdf57e379465f50bc5c03ab0e3cd08222875f69..1651bd483445c6433b2fd5b8992df50cda082773 100755 Binary files a/figures/SNR_distrib.pdf and b/figures/SNR_distrib.pdf differ diff --git a/figures/acc_vs_salience.pdf b/figures/acc_vs_salience.pdf index 57e7525946df22bfb3c276d3681fb55acae19be0..ba3d5604d9d4750492581e0638c6d23f2086139e 100755 Binary files a/figures/acc_vs_salience.pdf and b/figures/acc_vs_salience.pdf differ diff --git a/figures/freq_distrib.pdf b/figures/freq_distrib.pdf index c15e7dcb57d4d758676e982de1518cfb84cebe18..152e44f4ea567e0e740340b55802f7e8191b5f4c 100755 Binary files a/figures/freq_distrib.pdf and b/figures/freq_distrib.pdf differ diff --git a/figures/sample_spectrograms.pdf b/figures/sample_spectrograms.pdf index d5612b575d531c6742387eb24cd69a21f21dd915..d69a22f0a9c3f84bcc4463ca1c5ba00db8535ba5 100755 Binary files a/figures/sample_spectrograms.pdf and b/figures/sample_spectrograms.pdf differ diff --git a/figures/scatter_detec_scores.pdf b/figures/scatter_detec_scores.pdf deleted file mode 100755 index d87e9577d8845d40498a3184724996d6a36cb1fb..0000000000000000000000000000000000000000 Binary files a/figures/scatter_detec_scores.pdf and /dev/null differ diff --git a/figures/scatter_scores.pdf b/figures/scatter_scores.pdf index 94cdef687a6d6679831722fce8590b639eb09ec1..d1346e291fc64920c09c0a798a7c202950140773 100755 Binary files a/figures/scatter_scores.pdf and b/figures/scatter_scores.pdf differ diff --git a/figures/scatter_scores_detec.pdf b/figures/scatter_scores_detec.pdf new file mode 100644 index 0000000000000000000000000000000000000000..cbd0bfb4fe520b3669b399eeb4e387dfce5a319a Binary files /dev/null and b/figures/scatter_scores_detec.pdf differ diff --git a/figures/scatter_scores_columns.pdf b/figures/scatter_scores_thresholds.pdf similarity index 60% rename from figures/scatter_scores_columns.pdf rename to figures/scatter_scores_thresholds.pdf index ab2f6fb7df2ad8c893b7a86ea4f9df255420540d..b71dac96c95c18cbb00f4ae6b03b58115abeb4ea 100644 Binary files a/figures/scatter_scores_columns.pdf and b/figures/scatter_scores_thresholds.pdf differ diff --git a/figures/scores.pdf b/figures/scores.pdf deleted file mode 100755 index 9cf8b6ede74b8fa410bf2f1d8423c601c78ff3f5..0000000000000000000000000000000000000000 Binary files a/figures/scores.pdf and /dev/null differ diff --git a/plot_acc_vs_salience.py b/plot_acc_vs_salience.py index 9e60b3ce84d1d544f8c48d138265d83443daf862..624abef87718335b7a602d27277f88115da67a07 100755 --- a/plot_acc_vs_salience.py +++ b/plot_acc_vs_salience.py @@ -5,6 +5,8 @@ import matplotlib.pyplot as plt from glob import glob from p_tqdm import p_umap +colors = ['tab:blue', 'tab:orange', 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', 'tab:gray'] + cent_thr = 50 harm_thr = 0.5 @@ -16,7 +18,7 @@ algo_names = ['praat', 'pyin', 'basic', 'pesto-music', 'pesto-bio', 'crepe-other def fun(fn): df = pd.read_csv(fn) - + assert 'salience' in df.columns, f"missing salience value for {fn}, run python vocalisation_characterisation.py" df.annot = mir_eval.melody.hz2cents(df.annot) if df.salience.mean() < 0.15: return pd.DataFrame() @@ -53,7 +55,7 @@ for algo, name in zip(algos, algo_names): for i in range(2): ax[i].set_xlabel('salience') ax[i].grid() - ax[i].set_title(('' if i==0 else 'non-')+'Harmonic vocalisations') + ax[i].set_title(('H' if i==0 else 'Non-h')+'armonic vocalisations') ax[0].set_ylabel('mean pitch acc') ax[0].set_ylim(0, 1) diff --git a/plot_freq_distrib.py b/plot_freq_distrib.py index 05bfabbf521e5353afae0b77961f3793bee08f98..1570bd9699050ea9de0e0f6537d4d9e1ede841c4 100644 --- a/plot_freq_distrib.py +++ b/plot_freq_distrib.py @@ -1,3 +1,5 @@ +from svgpathtools import svg2paths +from svgpath2mpl import parse_path import pandas as pd, numpy as np import matplotlib.pyplot as plt from tqdm import tqdm @@ -7,10 +9,10 @@ from metadata import species np.seterr(divide = 'ignore') species_list = [ - 'wolves', 'spotted_hyenas', # 2 good salience & harmonicity + 'canids', 'spotted_hyenas', # 2 good salience & harmonicity 'bottlenose_dolphins', 'rodents', 'little_owls', # 3 good salience only - 'monk_parakeets', 'lions', 'orangutans', 'long_billed_hermits', # 4 good harmonicity only - 'hummingbirds', 'disk-winged_bats', 'Reunion_white_eyes', 'dolphins', 'la_Palma_chaffinches'] # 5 neither + 'monk_parakeets', 'lions', 'orangutans', 'long-billed_hermits', # 4 good harmonicity only + 'hummingbirds', 'disk-winged_bats', 'Reunion_grey_white_eyes', 'dolphins', 'La_Palma_chaffinches'] # 5 neither taxas = ['M', 'M', 'M', 'M', 'A', 'A', 'M', 'M', 'A', 'A', 'M', 'A', 'M', 'A'] @@ -29,7 +31,7 @@ for i, (specie, tax) in enumerate(zip(species_list, taxas)): dt = nfft * step / FS fdistrib, tdistrib, moddistrib = [], [], [] files = pd.Series(glob(wavpath)) - for fn in tqdm(files.sample(min(3000, len(files))), desc=specie): + for fn in tqdm(files, desc=specie): annot = pd.read_csv(f'{fn[:-4]}.csv').drop_duplicates(subset='Time').fillna(0) f0s, mask2 = mir_eval.melody.resample_melody_series(annot.Time, annot.Freq, annot.Freq > 0,\ np.arange(annot.Time.min()+1e-5, annot.Time.max(), dt), kind='linear', verbose=False) @@ -39,18 +41,26 @@ for i, (specie, tax) in enumerate(zip(species_list, taxas)): #moddistrib.extend(abs(np.diff(f0s[mask2.astype(bool)]))/dt) for j, data in enumerate([fdistrib, tdistrib, moddistrib]): - p = ax[j].violinplot(data, points=500, positions=[-i], vert=False, quantiles=[0.25, 0.5, 0.75]) - p['cquantiles'].set_color('black') + p = ax[j].violinplot(data, points=500, positions=[-i], vert=False) #, quantiles=[0.25, 0.5, 0.75]) p['bodies'][-1].set_facecolor('C0' if tax == 'M' else 'C1') p['bodies'][-1].set_alpha(1) p['cbars'].set_color('C0' if tax == 'M' else 'C1') p['cmaxes'].set_color('C0' if tax == 'M' else 'C1') p['cmins'].set_color('C0' if tax == 'M' else 'C1') -# ax[j].boxplot(data, positions=[-i], vert=False) + ax[j].vlines(np.quantile(data, [.25, .5, .75]), -i-.3, -i+.3, color='dimgrey') ax[0].set_xticks(10**np.arange(1, 6)) ax[2].set_xticks([-1e4, -1e2, -1, 1, 1e2, 1e4]) plt.yticks(-np.arange(len(species_list)), [s.replace('_',' ') for s in species_list]) -plt.tight_layout() +plt.tight_layout(rect=(0.02, 0, 1, 1)) + +ax2 = plt.axes([0,0,1,1], facecolor=(1,1,1,0)) +plt.axis('off') +ax2.set_xlim(0,1) +ax2.set_ylim(0,1) +for i, (specie, xoffset) in enumerate(zip(species_list, [.075, 0.015, -.01, .079, .061, 0.02, .09, .05, -.01, 0.01, 0.005, -.04, .07, -.02])): + icon = parse_path(svg2paths(f'svg/{specie}.svg')[1][0]['d']) + plt.scatter(0.05+xoffset, 0.89-i*.74/len(species_list), marker=icon, color='none', edgecolors='black', s=1000) + plt.savefig('figures/freq_distrib.pdf') diff --git a/plot_scores_bars.py b/plot_scores_bars.py deleted file mode 100644 index c6ad5bf397fed21196f168c49943bec7bf12e14c..0000000000000000000000000000000000000000 --- a/plot_scores_bars.py +++ /dev/null @@ -1,42 +0,0 @@ -import matplotlib.pyplot as plt -import pandas as pd, numpy as np -from metadata import species -import argparse - -algos = ['praat', 'pyin', 'basic', 'pesto', 'pesto_ft', 'tcrepe_ftoth', 'tcrepe_ftsp'] -metrics = ['Pitch acc', 'Chroma acc', 'Recall', 'Specificity'] - -species_list = [ - 'wolves','hyenas', 'bottlenose_dolphins', # 3 good salience & harmonicity - 'rodents','little_owl','white_eye', # 3 good salience only - 'lions','orangutans','parakeets','hummingbirds','long_billed','bats', # 6 good harmonicity only - 'dolphins','palmae'] # 4 neither - -parser = argparse.ArgumentParser() -parser.add_argument('--drop_noisy_bins', type=bool, help="drop noisy vocalisations", default=False) -parser.add_argument('--drop_noisy_vocs', type=bool, help="drop noisy STFT bins", default=False) -args = parser.parse_args() -drop_noisy_vocs, drop_noisy_bins = args.drop_noisy_vocs, args.drop_noisy_bins - -fig, ax = plt.subplots(nrows=2, ncols=2, figsize=(10, 5), sharex=True, sharey=True) -ax[0,0].set_ylim(0, 1) - -for i, metric in enumerate(metrics): - ok = pd.DataFrame() - for specie in species_list: - df = pd.read_csv(f'scores/{specie}_scores{"_minusvocs" if drop_noisy_vocs else ""}{"_minusbins" if drop_noisy_bins else ""}.csv', index_col=0) - df['Specificity'] = 1 - df['False alarm'] - ok.loc[specie.replace('_',' '), df.index] = df[metric] - - ok = ok[algos] - # bar plot - m_ax = ax[int(i//2), i%2] - ok.plot.bar(ax=m_ax, legend=None, rot=45, width=.6) - #m_ax.grid() - m_ax.set_title(metric) - if i%2==1: - m_ax.legend(bbox_to_anchor=(1,1)) - m_ax.vlines([2.5, 5.5, 11.5], 0, 1, linestyle='dashed', color='k') - -plt.tight_layout() -plt.savefig(f'figures/scores{"_minusvocs" if drop_noisy_vocs else ""}{"_minusbins" if drop_noisy_bins else ""}.pdf') diff --git a/plot_scores_columns.py b/plot_scores_columns.py index 57f610e9fe700f3a1498a11cf6f7af4a9dff0581..d875faa813140100d9d7a30f25ee936d73d1247c 100644 --- a/plot_scores_columns.py +++ b/plot_scores_columns.py @@ -2,13 +2,12 @@ import matplotlib.pyplot as plt from matplotlib.patches import Rectangle from matplotlib import colors import pandas as pd, numpy as np -from metadata import species +# from svg_pltmarker import get_marker_from_svg -#colors = ['#006BA4', '#FF800E', '#ABABAB', '#595959', '#5F9ED1', '#C85200', '#898989', '#A2C8EC', '#FFBC79', '#CFCFCF'] -colors = list(colors.TABLEAU_COLORS) +colors = ['tab:blue', 'tab:orange', 'tab:red', 'tab:purple'] +# colors = list(colors.TABLEAU_COLORS) # plt.rcParams['legend.title_fontsize'] = 'x-small' - markers = [ ('o', 'right', colors[0]), ('d', 'none', colors[0]), ('s', 'none', colors[1]), ('v', 'none', colors[1]), ('H', 'none', colors[1]), @@ -17,25 +16,25 @@ markers = [ species_list = [ - 'wolves', 'spotted_hyenas', # 2 good salience & harmonicity + 'canids', 'spotted_hyenas', # 2 good salience & harmonicity 'bottlenose_dolphins', 'rodents', 'little_owls', # 3 good salience only 'monk_parakeets', 'lions', 'orangutans', 'long-billed_hermits', # 4 good harmonicity only 'hummingbirds', 'disk-winged_bats', 'Reunion_grey_white_eyes', 'dolphins', 'La_Palma_chaffinches'] # 5 neither -algos = ['basic', 'pyin', 'pesto', 'praat', 'pesto_ft', 'tcrepe_ftoth', 'tcrepe_ftsp'] -algo_names = ['basic', 'pyin', 'pesto-music', 'praat', 'pesto-bio', 'crepe-other', 'crepe-target'] -metrics = ['Pitch acc'] #, 'Chroma acc'] -# metrics = ['Recall', 'Specificity', 'Vocalisation recall'] +algos = ['basic', 'pyin', 'pesto', 'praat', 'pesto_ft', 'tcrepe_ftoth', 'tcrepe_ftsp'] #, 'tcrepe_ftspV'] +algo_names = ['basic', 'pyin', 'pesto-music', 'praat', 'pesto-bio', 'crepe-heterosp.', 'crepe-consp.'] #, 'crepe-target\nviterbi'] +#metrics = ['Pitch acc', 'Chroma acc'] +metrics = ['Specificity', 'Recall', 'Vocalisation recall'] -fig, ax = plt.subplots(nrows=1, ncols=len(metrics), figsize=(10, 4.5), sharex=True, sharey=True) -#ax[0].set_yticks([0, .2, .4, .6, .8, 1]) -ax.set_ylim(0, 1) +fig, ax = plt.subplots(nrows=len(metrics), ncols=1, figsize=(9, 6), sharex=True, sharey=True) +ax[0].set_ylim(0, 1.05) +ax[0].set_yticks(np.arange(0, 1.1, .2)) algo_legend = [] for i, metric in enumerate(metrics): - m_ax = ax #ax[int(i//2), i%2] + m_ax = ax[i] #ax[int(i//2), i%2] m_ax.grid('both', axis='y') - m_ax.set_ylabel(metric, fontsize='medium') + m_ax.set_ylabel(metric.replace('acc', 'accuracy'), fontsize='medium') ok = pd.DataFrame() for j, (specie, marker) in enumerate(zip(species_list, markers)): @@ -43,25 +42,28 @@ for i, metric in enumerate(metrics): df['Specificity'] = 1 - df['False alarm'] df.rename(columns={'Voc. recall':'Vocalisation recall'}, inplace=True) ok.loc[specie, df.index] = df[metric] - - tt = m_ax.plot(np.arange(len(algos))-.3+j*0.6/len(species_list), ok.loc[specie, algos], marker=marker[0], color=marker[2], fillstyle=marker[1], markersize=8, label=specie.replace('_',' '), linestyle='none') + + # icon = get_marker_from_svg(filepath=f'svg/{specie}.svg') + # icon.vertices *= -1 + tt = m_ax.plot(np.arange(len(algos))-.3+j*0.6/len(species_list), ok.loc[specie, algos],\ + marker=marker[0], color=marker[2], markersize=7, fillstyle=marker[1], label=specie.replace('_',' '), linestyle='none') algo_legend.append(tt[0]) m_ax.set_xticks(range(len(algo_names))) m_ax.set_xticklabels(algo_names) #ax[1].set_xticklabels(algos, rotation=22) -plt.tight_layout(rect=(0, 0, 1, .87)) - +plt.tight_layout(rect=(0, 0, 1, .86), w_pad=0.01) species_list = [s.replace('_', ' ') for s in species_list] -leg = ax.legend(algo_legend[:2], species_list[:2], title='salient & harmonic', loc='lower left', bbox_to_anchor=(0, 1.02), fontsize='x-small') -ax.add_artist(leg) -leg = ax.legend(algo_legend[2:5], species_list[2:5], title='salient & non-harmonic', loc='lower left', bbox_to_anchor=(0.16, 1.02), fontsize='x-small') -ax.add_artist(leg) -leg = ax.legend(algo_legend[5:9], species_list[5:9], ncols=2, title='non-salient & harmonic', loc='lower left', bbox_to_anchor=(0.36, 1.02), fontsize='x-small') -ax.add_artist(leg) -leg = ax.legend(algo_legend[9:], species_list[9:], ncols=2, title='non-salient & non-harmonic', loc='lower left', bbox_to_anchor=(0.65, 1.02), fontsize='x-small') -ax.add_artist(leg) +m_ax = ax[0] +leg = m_ax.legend(algo_legend[:2], species_list[:2], title='salient & harmonic', loc='lower left', bbox_to_anchor=(-0.08, 1.04), fontsize='x-small', handleheight=3.15) +m_ax.add_artist(leg) +leg = m_ax.legend(algo_legend[2:5], species_list[2:5], title='salient & non-harmonic', loc='lower left', bbox_to_anchor=(0.1, 1.04), fontsize='x-small', handleheight=1.7) +m_ax.add_artist(leg) +leg = m_ax.legend(algo_legend[5:9], species_list[5:9], ncols=2, title='non-salient & harmonic', loc='lower left', bbox_to_anchor=(.32, 1.04), fontsize='x-small', handleheight=3.15) +m_ax.add_artist(leg) +leg = m_ax.legend(algo_legend[9:], species_list[9:], ncols=2, title='non-salient & non-harmonic', loc='lower left', bbox_to_anchor=(.635, 1.04), fontsize='x-small', handleheight=1.7) +m_ax.add_artist(leg) # ax.legend(loc='lower left', ncols=7, bbox_to_anchor=(0, 1.1), fontsize='x-small') -plt.savefig(f'figures/scatter_scores_columns.pdf') +plt.savefig(f'figures/scatter_scores_detec.pdf') diff --git a/plot_scores_scatter.py b/plot_scores_scatter.py deleted file mode 100644 index cf94b5dba93f206fc0b1dfc3e56f675a8ac006de..0000000000000000000000000000000000000000 --- a/plot_scores_scatter.py +++ /dev/null @@ -1,62 +0,0 @@ -import matplotlib.pyplot as plt -from matplotlib import colors -from matplotlib.patches import Rectangle -import pandas as pd, numpy as np -from metadata import species -import argparse - -markers = [['o','d'],['s','v','H'],['<','>','^','p'],['P','*','X','D','h']] - - -species_list = [ - ['wolves', 'spotted_hyenas'], # 2 good salience & harmonicity - ['bottlenose_dolphins', 'rodents', 'little_owls'], # 3 good salience only - ['monk_parakeets', 'lions', 'orangutans', 'long_billed_hermits'], # 4 good harmonicity only - ['hummingbirds', 'disk-winged_bats', 'Reunion_white_eyes', 'dolphins', 'la_Palma_chaffinches']] # 5 neither - -algos = ['praat', 'pyin', 'basic', 'pesto', 'pesto_ft', 'tcrepe_ftoth', 'tcrepe_ftsp'] -algo_names = ['praat', 'pyin', 'basic', 'pesto-music', 'pesto-bio', 'crepe-other', 'crepe-target'] -#metrics = ['Pitch acc', 'Chroma acc'] -metrics = ['Recall', 'Specificity', 'Vocalisation recall'] - -parser = argparse.ArgumentParser() -parser.add_argument('--drop_noisy_bins', type=bool, help="drop noisy vocalisations", default=False) -parser.add_argument('--drop_noisy_vocs', type=bool, help="drop noisy STFT bins", default=False) -args = parser.parse_args() -drop_noisy_vocs, drop_noisy_bins = args.drop_noisy_vocs, args.drop_noisy_bins - -fig, ax = plt.subplots(nrows=1, ncols=len(metrics), figsize=(10, 3.5), sharex=True, sharey=True) -#ax[0].set_yticks([0, .2, .4, .6, .8, 1]) -ax[0].set_ylim(0, 1) -algo_legend = [] - -for i, metric in enumerate(metrics): - ok = pd.DataFrame() - for specie in np.concatenate(species_list): - df = pd.read_csv(f'scores/{specie}_scores{"_minusvocs" if drop_noisy_vocs else ""}{"_minusbins" if drop_noisy_bins else ""}.csv', index_col=0) - df['Specificity'] = 1 - df['False alarm'] - df.rename(columns={'Voc. recall':'Vocalisation recall'}, inplace=True) - ok.loc[specie, df.index] = df[metric] - for j, algo in enumerate(algos): - for k, (species_grp, markers_grp) in enumerate(zip(species_list, markers)): - x = k-.3+j*.6/len(algos) - y = ok.loc[species_grp, algo].min() - h = ok.loc[species_grp, algo].max()-ok.loc[species_grp, algo].min() - rect = Rectangle((x, y), .6/len(algos), h, facecolor=list(colors.TABLEAU_COLORS)[j], alpha=.5) - if k==0: - algo_legend.append(rect) - ax[i].add_patch(rect) - for l, (specie, marker) in enumerate(zip(species_grp, markers_grp)): - if algo =='pesto' and specie=='LO': - print(ok.loc[specie, algo]) - ax[i].scatter(k - .3 + (j+.5) * .6/len(algos), ok.loc[specie, algo], marker=marker, s=10, color='grey', label=specie.replace('_',' ') if j==0 else None) - - m_ax = ax[i] #ax[int(i//2), i%2] - m_ax.grid('both', axis='y') - m_ax.set_title(metric, fontsize='medium') -plt.xticks(np.arange(len(species_list)), ['S-H','S-nH.','nS-H.','nS-nH.']) -#ax[1].set_xticklabels(algos, rotation=22) -plt.tight_layout(rect=(0, 0, .87, .9)) -ax[0].legend(loc='lower left', ncols=7, bbox_to_anchor=(0, 1.1), fontsize='x-small') -ax[-1].legend(algo_legend, algo_names, bbox_to_anchor=(1,1)) -plt.savefig(f'figures/scatter_detec_scores{"_minusvocs" if drop_noisy_vocs else ""}{"_minusbins" if drop_noisy_bins else ""}.pdf') diff --git a/plot_snr_distrib.py b/plot_snr_distrib.py index cb8728c144a149071cba2dcb577d58b7ff5a5f80..698b4881196af21988ef315e258ca6768f0e39c5 100755 --- a/plot_snr_distrib.py +++ b/plot_snr_distrib.py @@ -1,15 +1,18 @@ +from svgpathtools import svg2paths +from svgpath2mpl import parse_path import pandas as pd, numpy as np import matplotlib.pyplot as plt from p_tqdm import p_umap from glob import glob from metadata import species np.seterr(divide = 'ignore') +plt.style.use('tableau-colorblind10') species_list = [ - 'wolves', 'spotted_hyenas', # 2 good salience & harmonicity + 'canids', 'spotted_hyenas', # 2 good salience & harmonicity 'bottlenose_dolphins', 'rodents', 'little_owls', # 3 good salience only - 'monk_parakeets', 'lions', 'orangutans', 'long_billed_hermits', # 4 good harmonicity only - 'hummingbirds', 'disk-winged_bats', 'Reunion_white_eyes', 'dolphins', 'la_Palma_chaffinches'] # 5 neither + 'monk_parakeets', 'lions', 'orangutans', 'long-billed_hermits', # 4 good harmonicity only + 'hummingbirds', 'disk-winged_bats', 'Reunion_grey_white_eyes', 'dolphins', 'La_Palma_chaffinches'] # 5 neither taxas = ['M', 'M', 'M', 'M', 'A', 'A', 'M', 'M', 'A', 'A', 'M', 'A', 'M', 'A'] @@ -33,12 +36,17 @@ for i, (specie, taxa) in enumerate(zip(species_list, taxas)): SHR = SHR[salience > .2] harmonicity = harmonicity[salience > .2] for j, data in enumerate([salience, SHR, harmonicity]): - p = ax[j].violinplot(data, points=500, positions=[-i], vert=False, quantiles=[0.25, 0.5, 0.75], showextrema=False) + p = ax[j].violinplot(data, points=500, positions=[-i], vert=False, showextrema=False) p['bodies'][-1].set_facecolor('C0' if taxa == 'M' else 'C1') p['bodies'][-1].set_alpha(1) - p['cquantiles'].set_color('black') - -plt.tight_layout() + ax[j].vlines(np.quantile(data, [.25, .5, .75]), -i-.3, -i+.3, color='dimgrey') + +plt.tight_layout(rect=(0.02, 0, 1, 1)) +ax2 = plt.axes([0,0,1,1], facecolor=(1,1,1,0)) +plt.axis('off') +ax2.set_xlim(0,1) +ax2.set_ylim(0,1) +for i, (specie, xoffset) in enumerate(zip(species_list, [.075, 0.015, -.01, .079, .061, 0.02, .09, .05, -.01, 0., 0.005, -.04, .07, -.02])): + icon = parse_path(svg2paths(f'svg/{specie}.svg')[1][0]['d']) + plt.scatter(0.05+xoffset, 0.89-i*.74/len(species_list), marker=icon, color='none', edgecolors='black', s=1000) plt.savefig('figures/SNR_distrib.pdf') -plt.close() - diff --git a/print_pred_samples.py b/print_pred_samples.py index 691da79af2c759d7b61772d5421a22e8ea93235a..c831f63bf674e305dcf354e5fd9fa03a49ae822b 100644 --- a/print_pred_samples.py +++ b/print_pred_samples.py @@ -1,25 +1,37 @@ import pandas as pd, numpy as np import matplotlib.pyplot as plt -import librosa, mir_eval +from matplotlib.colors import to_hex as to_rgba +from matplotlib.lines import Line2D +import librosa from scipy import signal from glob import glob from metadata import species algos = ['praat', 'pesto_ft', 'tcrepe_ftsp'] +algo_names = ['PRAAT', 'pesto-bio', 'crepe-consp.'] +colors = ['tab:orange', 'tab:red', 'tab:purple'] species_list = [ - 'wolves', 'spotted_hyenas', # 2 good salience & harmonicity + 'canids', 'spotted_hyenas', # 2 good salience & harmonicity 'bottlenose_dolphins', 'rodents', 'little_owls', # 3 good salience only - 'hummingbirds', 'disk-winged_bats', 'Reunion_white_eyes', 'monk_parakeets', 'lions', 'orangutans', 'long_billed_hermits', # 7 good harmonicity only - 'dolphins', 'la_Palma_chaffinches'] # 2 neither + 'hummingbirds', 'disk-winged_bats', 'Reunion_grey_white_eyes', 'monk_parakeets', 'lions', 'orangutans', 'long-billed_hermits', # 7 good harmonicity only + 'dolphins', 'La_Palma_chaffinches'] # 2 neither + +names = [ + 'canids', 'spotted\nhyenas', # 2 good salience & harmonicity + 'bottlenose\ndolphins', 'rodents', 'little owls', # 3 good salience only + 'hummingbirds', 'disk-winged\nbats', 'Reuniongrey\nwhite eyes', 'monk\nparakeets', 'lions', 'orangutans', 'long-billed\nhermits', # 7 good harmonicity only + 'dolphins', 'La Palma\nchaffinches'] # 2 neither + fig, ax = plt.subplots(nrows=len(species_list), ncols=5, figsize=(12, 15), sharey='row') -for i, specie in enumerate(species_list): +for i, (specie, name) in enumerate(zip(species_list, names)): wavpath, FS, nfft, downsample, step = species[specie].values() thrs = pd.read_csv(f'scores/{specie}_scores.csv', index_col=0).threshold files = pd.Series(glob(wavpath)).sample(5) dt = nfft * step / FS # winsize / 8 + fmax = 0 for j, fn in enumerate(files): # load signal and compute spetrogram sig, fs = librosa.load(fn, sr=FS) @@ -32,15 +44,42 @@ for i, specie in enumerate(species_list): plt.autoscale(False) ax[i, j].imshow(S, vmin=np.quantile(S, .2), vmax=np.quantile(S, .98), origin='lower', aspect='auto', extent=[0, len(sig)/fs, 0, fs/2/1000], cmap='Greys') plt.autoscale(True) - ax[i, j].scatter(df.dropna(subset='annot').time, df.dropna(subset='annot').annot/1000, label='annot') - for algo in algos: -# if not df[algo+'_f0'].isna().all(): - ax[i, j].scatter(df[df[algo+'_conf']>thrs[algo]].time, df[df[algo+'_conf']>thrs[algo]][algo+'_f0']/1000, label=algo, s=3) - ax[i, j].set_ylim(0, df.annot.max()*2/1000) + ax[i, j].scatter(df.dropna(subset='annot').time, df.dropna(subset='annot').annot/1000, label='annot', color='tab:blue') + # ax[i, j].plot(df.dropna(subset='annot').time, df.dropna(subset='annot').annot/1000, linestyle='none', marker='o', color='blue', markersize=10, fillstyle='none') + for algo, algo_name, color in zip(algos, algo_names, colors): + ax[i, j].scatter(df[df[algo+'_conf']>thrs[algo]].time, df[df[algo+'_conf']>thrs[algo]][algo+'_f0']/1000, label=algo_name, s=3, color=color) ax[i,j].set_xticks(np.arange(0, len(sig)/fs, 0.1), "") if j == 0: - ax[i,j].set_ylabel(specie.replace('_', ' ').replace(' ', '\n', 1)) + ax[i,j].set_ylabel(name) + fmax = max(fmax, df.annot.max()*2/1000) + ax[i, 0].set_ylim(0, fmax) + + +plt.tight_layout(rect=(0, 0, 0.95, .975), pad=0.1, w_pad=0.11, h_pad=-0.05) +leg = ax[0,2].legend(loc='lower center', ncols=4, bbox_to_anchor=(0.5, 1.05)) +leg.legend_handles[1]._sizes = leg.legend_handles[0]._sizes +leg.legend_handles[2]._sizes = leg.legend_handles[0]._sizes +leg.legend_handles[3]._sizes = leg.legend_handles[0]._sizes +ax[0,2].add_artist(leg) + +ax2 = plt.axes([0,0,1,1], facecolor=(1,1,1,0)) +plt.axis('off') + +ax2.text(.965, .86, 'Salient and Harmonic', rotation=270) +line = Line2D([.96, .96], [.965, .845], lw=3., color='k', alpha=0.4) +ax2.add_line(line) + +ax2.text(.965, .67, 'Salient and non-harmonic', rotation=270) +line = Line2D([.96, .96], [.825, .637], lw=3., color='k', alpha=0.4) +ax2.add_line(line) + +ax2.text(.965, .3, 'Non-salient and Harmonic', rotation=270) +line = Line2D([.96, .96], [.62, .145], lw=3., color='k', alpha=0.4) +ax2.add_line(line) + +ax2.text(.965, .001, 'Non-salient and Non-harmonic', rotation=270) +line = Line2D([.96, .96], [.13, .01], lw=3., color='k', alpha=0.4) +ax2.add_line(line) + -#plt.legend() -plt.tight_layout(pad=0.1, w_pad=0.1, h_pad=-0.05) plt.savefig(f'figures/sample_spectrograms.pdf')