import plotstyle_plt import numpy as np import matplotlib.pyplot as plt from itertools import product from thunderhopper.filetools import search_files from thunderhopper.modeltools import load_data from misc_functions import get_saturation from color_functions import load_colors from plot_functions import hide_axis, ylimits, xlabel, ylabel, title_subplot,\ plot_line, strip_zeros, time_bar,\ letter_subplot, letter_subplots from IPython import embed def plot_snippets(axes, time, snippets, ymin=None, ymax=None, **kwargs): ymin, ymax = ylimits(snippets, minval=ymin, maxval=ymax, pad=0.05) for i, ax in enumerate(axes): plot_line(ax, time, snippets[:, ..., i], ymin=ymin, ymax=ymax, **kwargs) return None def plot_curves(ax, scales, measures, fill_kwargs={}, **kwargs): if measures.ndim == 1: ax.plot(scales, measures, **kwargs)[0] return measures median_measure = np.median(measures, axis=1) spread_measure = [np.percentile(measures, 25, axis=1), np.percentile(measures, 75, axis=1)] ax.plot(scales, median_measure, **kwargs)[0] ax.fill_between(scales, *spread_measure, **fill_kwargs) return median_measure def show_saturation(ax, scales, measures, high=0.95, **kwargs): high_ind = get_saturation(measures, high=high)[1] return ax.plot(scales[high_ind], 0, transform=ax.get_xaxis_transform(), marker='o', ms=10, zorder=6, clip_on=False, **kwargs) # GENERAL SETTINGS: target_species = [ 'Chorthippus_biguttulus', 'Chorthippus_mollis', 'Chrysochraon_dispar', 'Euchorthippus_declivus', 'Gomphocerippus_rufus', 'Omocestus_rufipes', 'Pseudochorthippus_parallelus', ][5] example_file = { 'Chorthippus_biguttulus': 'Chorthippus_biguttulus_GBC_94-17s73.1ms-19s977ms', 'Chorthippus_mollis': 'Chorthippus_mollis_DJN_41_T28C-46s4.58ms-1m15s697ms', 'Chrysochraon_dispar': 'Chrysochraon_dispar_DJN_26_T28C_DT-32s134ms-34s432ms', 'Euchorthippus_declivus': 'Euchorthippus_declivus_FTN_79-2s167ms-2s563ms', 'Gomphocerippus_rufus': 'Gomphocerippus_rufus_FTN_91-3-884ms-10s427ms', 'Omocestus_rufipes': 'Omocestus_rufipes_DJN_32-40s724ms-48s779ms', 'Pseudochorthippus_parallelus': 'Pseudochorthippus_parallelus_GBC_88-6s678ms-9s32.3ms' }[target_species] raw_path = search_files(target_species, incl='raw', dir='../data/inv/full/condensed/')[0] norm_path = search_files(target_species, incl='norm', dir='../data/inv/full/condensed/')[0] snip_path = search_files(example_file, dir='../data/inv/full/')[0] trace_path = search_files(target_species, dir='../data/inv/full/collected/')[0] ref_path = '../data/inv/full/ref_measures.npz' save_path = '../figures/fig_invariance_full.pdf' stages = ['filt', 'env', 'log', 'inv', 'conv', 'feat'] load_kwargs = dict( files=stages, keywords=['scales', 'snip', 'measure'] ) # GRAPH SETTINGS: fig_kwargs = dict( figsize=(32/2.54, 20/2.54), ) super_grid_kwargs = dict( nrows=2, ncols=1, wspace=0, hspace=0, left=0, right=1, bottom=0, top=1, height_ratios=[3, 2] ) subfig_specs = dict( snip=(0, 0), big=(1, 0), ) snip_grid_kwargs = dict( nrows=len(stages), ncols=None, wspace=0.1, hspace=0.4, left=0.08, right=0.95, bottom=0.08, top=0.95 ) big_grid_kwargs = dict( nrows=1, ncols=3, wspace=0.2, hspace=0, left=snip_grid_kwargs['left'], right=0.96, bottom=0.2, top=0.95 ) # PLOT SETTINGS: fs = dict( lab_norm=16, lab_tex=20, letter=22, tit_norm=16, tit_tex=20, bar=16, ) colors = load_colors('../data/stage_colors.npz') lw = dict( filt=0.25, env=0.25, log=0.25, inv=0.25, conv=0.25, feat=1, big=3, plateau=1.5, ) xlabels = dict( big='scale $\\alpha$', ) ylabels = dict( filt='$x_{\\text{filt}}$', env='$x_{\\text{env}}$', log='$x_{\\text{db}}$', inv='$x_{\\text{inv}}$', conv='$c_i$', feat='$f_i$', big=['intensity', 'rel. intensity', 'norm. intensity'] ) xlab_big_kwargs = dict( y=0, fontsize=fs['lab_norm'], ha='center', va='bottom', ) ylab_snip_kwargs = dict( x=0, fontsize=fs['lab_tex'], rotation=0, ha='left', va='center' ) ylab_big_kwargs = dict( x=-0.12, fontsize=fs['lab_norm'], ha='center', va='bottom', ) yloc = dict( filt=3000, env=1000, log=50, inv=20, conv=2, feat=1, ) title_kwargs = dict( x=0.5, yref=1, ha='center', va='top', fontsize=fs['tit_norm'], ) letter_snip_kwargs = dict( x=0, yref=0.5, ha='left', va='center', fontsize=fs['letter'], ) letter_big_kwargs = dict( x=0, y=1, ha='left', va='bottom', fontsize=fs['letter'], ) bar_time = 5 bar_kwargs = dict( dur=bar_time, y0=-0.25, y1=-0.1, xshift=1, color='k', lw=0, clip_on=False, text_pos=(-0.1, 0.5), text_str=f'${bar_time}\\,\\text{{s}}$', text_kwargs=dict( fontsize=fs['bar'], ha='right', va='center', ) ) plateau_settings = dict( low=0.05, high=0.95, first=True, last=True, condense=None, ) plateau_line_kwargs = dict( lw=lw['plateau'], ls='--', zorder=1, ) plateau_dot_kwargs = dict( marker='o', markersize=8, markeredgewidth=1, clip_on=False, ) # EXECUTION: # Load invariance data: raw_data, config = load_data(raw_path, files='scales', keywords='mean') norm_data, _ = load_data(norm_path, files='scales', keywords='mean') scales = raw_data['scales'] # Load snippet data: snip, _ = load_data(snip_path, files='example_scales', keywords='snip') t_full = np.arange(snip['snip_filt'].shape[0]) / config['rate'] snip_scales = snip['example_scales'] # Adjust grid parameters: snip_grid_kwargs['ncols'] = snip_scales.size # Prepare overall graph: fig = plt.figure(**fig_kwargs) super_grid = fig.add_gridspec(**super_grid_kwargs) # Prepare stage-specific snippet axes: snip_subfig = fig.add_subfigure(super_grid[subfig_specs['snip']]) snip_grid = snip_subfig.add_gridspec(**snip_grid_kwargs) snip_axes = np.zeros((snip_grid.nrows, snip_grid.ncols), dtype=object) for i, j in product(range(snip_grid.nrows), range(snip_grid.ncols)): ax = snip_subfig.add_subplot(snip_grid[i, j]) ax.set_xlim(t_full[0], t_full[-1]) ax.yaxis.set_major_locator(plt.MultipleLocator(yloc[stages[i]])) hide_axis(ax, 'bottom') if i == 0: title = title_subplot(ax, f'$\\alpha={strip_zeros(snip_scales[j])}$', ref=snip_subfig, **title_kwargs) if j == 0: ylabel(ax, ylabels[stages[i]], **ylab_snip_kwargs, transform=snip_subfig.transSubfigure) else: hide_axis(ax, 'left') snip_axes[i, j] = ax time_bar(snip_axes[-1, -1], **bar_kwargs) letter_subplot(snip_subfig, 'a', ref=title, **letter_snip_kwargs) # Prepare analysis axes: big_subfig = fig.add_subfigure(super_grid[subfig_specs['big']]) big_grid = big_subfig.add_gridspec(**big_grid_kwargs) big_axes = np.zeros((big_grid.ncols,), dtype=object) for i in range(big_grid.ncols): ax = big_subfig.add_subplot(big_grid[0, i]) ax.set_xlim(scales[0], scales[-1]) ax.set_xscale('symlog', linthresh=scales[1], linscale=0.5) ax.set_yscale('symlog', linthresh=0.01, linscale=0.1) xlabel(ax, xlabels['big'], transform=big_subfig, **xlab_big_kwargs) ylabel(ax, ylabels['big'][i], **ylab_big_kwargs) big_axes[i] = ax letter_subplots(big_axes, 'bc', **letter_big_kwargs) if False: # Plot filtered snippets: plot_snippets(snip_axes[0, :], t_full, snip['snip_filt'], c=colors['filt'], lw=lw['filt']) # Plot envelope snippets: plot_snippets(snip_axes[1, :], t_full, snip['snip_env'], ymin=0, c=colors['env'], lw=lw['env']) # Plot logarithmic snippets: plot_snippets(snip_axes[2, :], t_full, snip['snip_log'], c=colors['log'], lw=lw['log']) # Plot invariant snippets: plot_snippets(snip_axes[3, :], t_full, snip['snip_inv'], c=colors['inv'], lw=lw['inv']) # Plot kernel response snippets: plot_snippets(snip_axes[4, :], t_full, snip['snip_conv'], c=colors['conv'], lw=lw['conv']) # Plot feature snippets: plot_snippets(snip_axes[5, :], t_full, snip['snip_feat'], ymin=0, ymax=1, c=colors['feat'], lw=lw['feat']) # Plot analysis results: for stage in stages: # Get average unnormed measure across recordings: raw_measure = raw_data[f'mean_{stage}'].mean(axis=-1) # Plot unmodified intensity measures: curve = plot_curves(big_axes[0], scales, raw_measure, c=colors[stage], lw=lw['big'], fill_kwargs=dict(color=colors[stage], alpha=0.25)) # Indicate saturation point: if stage in ['log', 'inv', 'conv', 'feat']: ind = get_saturation(curve, **plateau_settings)[1] scale = scales[ind] big_axes[0].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, transform=big_axes[0].get_xaxis_transform()) big_axes[0].plot(scale, 0, mfc=colors[stage], mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, transform=big_axes[0].get_xaxis_transform()) big_axes[0].vlines(scale, big_axes[0].get_ylim()[0], curve[ind], color=colors[stage], **plateau_line_kwargs) # Get average noise-related measure across recordings: norm_measure = norm_data[f'mean_{stage}'].mean(axis=-1) # Plot noise-related intensity measure: curve = plot_curves(big_axes[1], scales, norm_measure, c=colors[stage], lw=lw['big'], fill_kwargs=dict(color=colors[stage], alpha=0.25)) # Indicate saturation point: if stage in ['log', 'inv', 'conv', 'feat']: big_axes[1].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, transform=big_axes[1].get_xaxis_transform()) big_axes[1].plot(scale, 0, mfc=colors[stage], mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, transform=big_axes[1].get_xaxis_transform()) big_axes[1].vlines(scale, big_axes[1].get_ylim()[0], curve[ind], color=colors[stage], **plateau_line_kwargs) # Normalize measure to [0, 1]: min_measure = raw_measure.min(axis=0) max_measure = raw_measure.max(axis=0) norm_measure = (raw_measure - min_measure) / (max_measure - min_measure) # Plot range-normalized intensity measure: curve = plot_curves(big_axes[2], scales, norm_measure, c=colors[stage], lw=lw['big'], fill_kwargs=dict(color=colors[stage], alpha=0.25)) # Indicate saturation point: if stage in ['log', 'inv', 'conv', 'feat']: big_axes[2].plot(scale, 0, c='w', alpha=1, zorder=5.5, **plateau_dot_kwargs, transform=big_axes[2].get_xaxis_transform()) big_axes[2].plot(scale, 0, mfc=colors[stage], mec='k', alpha=0.75, zorder=6, **plateau_dot_kwargs, transform=big_axes[2].get_xaxis_transform()) big_axes[2].vlines(scale, big_axes[2].get_ylim()[0], curve[ind], color=colors[stage], **plateau_line_kwargs) if save_path is not None: fig.savefig(save_path) plt.show() print('Done.') embed()