123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- """Create panels for figures. Helper module."""
- import numpy as np
- from .util import (stackmean, get_idx_match, contrast_log_scale, replace_imshow_ticklabels,
- ori_con_2d, circ_gaussian, hyper_ratio, wrapped_gaussian, von_mises)
- import matplotlib.pyplot as plt
- from cycler import cycler
- import datajoint as dj
- from mpl_toolkits.axes_grid1.inset_locator import InsetPosition
- from statsmodels.distributions.empirical_distribution import ECDF
- from scipy.stats import sem
- def kernels(kerns, dtopt, dtrange, ax=None, key=None, prop='grat_orientation'):
- if ax is None:
- fig, ax = plt.subplots()
- kern = np.stack(kerns['t_kernel'].groupby(prop).apply(stackmean))
- propvals = np.unique(kerns.index.get_level_values(prop))
- if prop == 'grat_orientation':
- kern = np.concatenate((kern, kern[0][np.newaxis, :]))
- propvals = np.concatenate((propvals, np.array([180]))).astype(int)
- im = ax.imshow(kern[:, :30]*1000, origin='lower', aspect='auto')
- dtidx = np.where(np.isclose(dtrange, dtopt))[0]
- ax.vlines(dtidx, -0.5, kern.shape[0]-0.5)
- ax.set_ylabel(prop[5].capitalize() + prop[6:])
- if plt.rcParams['text.usetex']:
- ax.set_xlabel(r'$\delta t$ (s)')
- else:
- ax.set_xlabel(r'dt (s)')
- replace_imshow_ticklabels(ax, dtrange[:30], propvals)
- cbar = plt.colorbar(im, ax=ax)
- cbar.set_label('Firing (Hz)', rotation=270, labelpad=7)
- return cbar
- def opt_dt_distr_exc_inh(exc_t_opts, inh_t_opts, t_opts, ax=None, excitcol='darkorange',
- inhibcol='teal'):
- if ax is None:
- fig, ax = plt.subplots()
- _, bins, _ = ax.hist(exc_t_opts, color=excitcol, bins='doane')
- ax.hist(inh_t_opts, color=inhibcol, bins=bins)
- xlim = ax.get_xlim()
- ax.set_xlim([0, xlim[1]])
- ax7a = ax.twinx()
- ecdf = ECDF(t_opts)
- ax7a.plot(ecdf.x, ecdf.y, color='k')
- ax7a.set_ylim([0, 1.01])
- if plt.rcParams['text.usetex']:
- ax.set_xlabel(r'Optimal $\delta t$ (s)')
- else:
- ax.set_xlabel('Optimal dt (s)')
- ax.set_ylabel('N')
- ax7a.set_ylabel('Proportion')
- ax7a.set_yticks([0, 0.5, 1])
- ax7a.spines['right'].set_bounds(0, 1)
- ax7a.spines['right'].set_visible(True)
- ax.spines['bottom'].set_bounds(*ax.get_xlim())
- def oricon_matrix(ax, data, cbar=False):
- df = data
- m = df.pivot_table('p_spike_stim', 'grat_orientation', 'grat_contrast')
- m = np.concatenate((m.values, m.values[0][np.newaxis, :]))*1000 # convert to Hz
- im = ax.imshow(m, origin='lower')
- if cbar:
- bar = plt.colorbar(im, ax=ax)
- bar.set_label('Firing rate (Hz)')
- else:
- bar = None
- ax.set_xlabel('Contrast')
- ax.set_ylabel('Orientation ($^{\circ}$)')
- contrasts = np.unique(df.index.get_level_values('grat_contrast')).round(2)
- orientations = np.linspace(0, 180, 13, endpoint=True).astype(int)
- replace_imshow_ticklabels(ax, contrasts, orientations)
- return ax, bar
- def wave_shapes(wforms, ax=None, excitcol='darkorange', inhibcol='teal', annotate=False):
- if ax is None:
- fig, ax = plt.subplots()
- wforms['wave'] = wforms.apply(
- lambda x: x['u_wave'][np.where(x['u_chans'] == x['u_maxchan'])[0][0]], axis=1)
- wforms['normwave'] = wforms.wave.apply(lambda x: x / np.abs(np.min(x)))
- wforms['ip_wave'] = wforms.normwave.apply(
- lambda x: np.interp(np.linspace(0, len(x), 120), np.arange(len(x)), x))
- wforms['al_wave'] = wforms.ip_wave.apply(lambda x: np.roll(x, 29 - np.argmin(x)))
- wtime = np.linspace(0, 120 * 0.017, 120)
- colors = [excitcol, inhibcol]
- for c, (gname, g) in zip(colors, wforms.groupby('unit_type')):
- ax.plot(wtime, np.stack(g['al_wave']).T, color=c, alpha=0.1)
- exmean = np.mean(wforms.query('unit_type=="excit"')['al_wave'], axis=0)
- inmean = np.mean(wforms.query('unit_type=="inhib"')['al_wave'], axis=0)
- ax.plot(wtime, exmean, color=excitcol)
- ax.plot(wtime, inmean, color=inhibcol)
- ax.set_xlabel('Time (ms)')
- ax.set_ylabel('Voltage')
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- ax.spines['left'].set_bounds(ax.dataLim.ymin, ax.dataLim.ymax)
- if annotate:
- ax.vlines(wtime[np.argmin(inmean)], np.min(inmean), 1.2*np.max(inmean),
- linestyles='dashed', color='k', zorder=3, linewidth=1)
- ax.vlines(wtime[np.argmax(inmean)], np.max(inmean), 1.2*np.max(inmean),
- linestyles='dashed', color='k', zorder=3, linewidth=1)
- ax.hlines(1.2*np.max(inmean), wtime[np.argmin(inmean)], wtime[np.argmax(inmean)],
- color='k', zorder=3, linewidth=1)
- peak = np.where(inmean >= 0.5*np.max(inmean))[0]
- ax.vlines(wtime[peak[0]], 0.5*np.max(inmean), -0.5, linestyles='dashed', color='k',
- zorder=3, linewidth=1)
- ax.vlines(wtime[peak[-1]], 0.5*np.max(inmean), -0.5, linestyles='dashed', color='k',
- zorder=3, linewidth=1)
- ax.hlines(-0.5, wtime[peak[0]], wtime[peak[-1]], color='k', zorder=3, linewidth=1)
- def wave_shapes_lgn(wforms, ax=None, color='k', annotate=False):
- if ax is None:
- fig, ax = plt.subplots()
- wforms['wave'] = wforms.apply(
- lambda x: x['u_wave'][np.where(x['u_chans'] == x['u_maxchan'])[0][0]], axis=1)
- wforms['normwave'] = wforms.wave.apply(lambda x: x / np.abs(np.min(x)))
- wforms['ip_wave'] = wforms.normwave.apply(
- lambda x: np.interp(np.linspace(0, len(x), 120), np.arange(len(x)), x))
- wforms['al_wave'] = wforms.ip_wave.apply(lambda x: np.roll(x, 29 - np.argmin(x)))
- wtime = np.linspace(0, 120 * 0.017, 120)
- ax.plot(wtime, np.stack(wforms['al_wave']).T, color=color, alpha=0.1)
- mean = np.mean(wforms['al_wave'], axis=0)
- ax.plot(wtime, mean, color=color)
- ax.set_xlabel('Time (ms)')
- ax.set_ylabel('Voltage')
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- ax.spines['left'].set_bounds(ax.dataLim.ymin, ax.dataLim.ymax)
- def wave_props(non_rc_props, rc_props, ax=None, excitcol='darkorange', inhibcol='teal', markeredgewidth=0.2,
- **plotkwargs):
- if ax is None:
- fig, ax = plt.subplots()
- colors = [excitcol, inhibcol]
- for c, (gname, g) in zip(colors, non_rc_props.groupby('unit_type')):
- ax.plot(g['fwhm_peak'], g['t2p_time'], '.', color=c, alpha=0.25, markersize=4, **plotkwargs)
- for c, (gname, g) in zip(colors, rc_props.groupby('unit_type')):
- ax.plot(g['fwhm_peak'], g['t2p_time'], '.', color=c,
- markeredgewidth=markeredgewidth, alpha=0.5, markersize=7, **plotkwargs)
- ax.set_xlabel('Fwhm_peak (ms)')
- ax.set_ylabel('T2p_time (ms)')
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- ax.spines['left'].set_bounds(ax.dataLim.ymin, ax.dataLim.ymax)
- def wave_props_lgn(non_rc_props, rc_props, ax=None, color='k', markeredgewidth=0.2,
- **plotkwargs):
- if ax is None:
- fig, ax = plt.subplots()
- ax.plot(non_rc_props['fwhm_peak'], non_rc_props['t2p_time'], '.', color=color, alpha=0.25, markersize=4, **plotkwargs)
- ax.plot(rc_props['fwhm_peak'], rc_props['t2p_time'], '.', color=color,
- markeredgewidth=markeredgewidth, alpha=0.5, markersize=7, **plotkwargs)
- ax.set_xlabel('Fwhm_peak (ms)')
- ax.set_ylabel('T2p_time (ms)')
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- ax.spines['left'].set_bounds(ax.dataLim.ymin, ax.dataLim.ymax)
- def daterrsvd(datdf, svddf, dtrange, axs=None, cbar=False, cbaraxs=None):
- if axs is None:
- fig, (ax1, ax2, ax3) = plt.subplots(1, 3)
- fig.suptitle(key)
- else:
- assert len(axs) == 3
- ax1, ax2, ax3 = axs
- # prepare data
- dat = datdf.pivot_table('p_spike_stim', 'grat_orientation', 'grat_contrast').values
- # prepare svd
- svddf['p_svd'] = svddf.apply(lambda x: x.svd_s_kernel[get_idx_match(x.dt_maxresponse,
- dtrange)], axis=1)
- svddf['p_err'] = svddf.apply(lambda x: x.err_s_kernel[get_idx_match(x.dt_maxresponse,
- dtrange)], axis=1)
- svd = svddf.pivot_table('p_svd', 'grat_orientation', 'grat_contrast').values
- svderr = svddf.pivot_table('p_err', 'grat_orientation', 'grat_contrast').values
- # wrap orientation domain
- dat = np.vstack((dat, dat[0, :]))
- svd = np.vstack((svd, svd[0, :]))
- svderr = np.vstack((svderr, svderr[0, :]))
- # prepare ticklabels
- oris = np.linspace(0, 180, 13).astype(int)
- cons = np.unique(datdf.index.get_level_values('grat_contrast'))
- # plot
- ims = []
- for ax, mat in zip([ax1, ax2, ax3], [dat, svd, svderr]):
- im = ax.imshow(mat*1000, origin='lower') # go from probability to Hz
- ims.append(im)
- replace_imshow_ticklabels(ax, cons, oris)
- # adjust labels
- ax2.set_yticklabels([])
- ax3.set_yticklabels([])
- ax1.set_ylabel('Orientation')
- for ax in [ax1, ax2, ax3]:
- ax.set_xlabel('Contrast')
- if cbar:
- if cbaraxs is None:
- cb1 = plt.colorbar(ims[1], ax=axs[1])
- cb2 = plt.colorbar(ims[2], ax=axs[2])
- else:
- cb1 = plt.colorbar(ims[1], cbaraxs[0])
- cb2 = plt.colorbar(ims[2], cbaraxs[1])
- return cb1, cb2
- def svd_vs_spatcorr(df, ax=None, exc_color='darkorange',
- inh_color='teal'):
- if ax is None:
- fig, ax = plt.subplots()
- inv_df = df.query('g_z_opt<=1.96 or power_opt>0.95')
- dep_df = df.query('g_z_opt>1.96 and power_opt<=0.95')
- e_inv_df = inv_df.query('unit_type=="excit"')
- i_inv_df = inv_df.query('unit_type=="inhib"')
- e_dep_df = dep_df.query('unit_type=="excit"')
- i_dep_df = dep_df.query('unit_type=="inhib"')
- ax.scatter(1-e_inv_df['power_opt'], e_inv_df['g_z_opt'], color=exc_color)
- ax.scatter(1-i_inv_df['power_opt'], i_inv_df['g_z_opt'], color=inh_color)
- ax.scatter(1-e_dep_df['power_opt'], e_dep_df['g_z_opt'], color=exc_color, alpha=0.5)
- ax.scatter(1-i_dep_df['power_opt'], i_dep_df['g_z_opt'], color=inh_color, alpha=0.5)
- ax.hlines(1.96, 0, 0.95, linestyles='dashed', alpha=0.5)
- ax.vlines(0.05, 1.96, np.max(df['g_z_opt']), linestyles='dashed',
- alpha=0.5)
- ax.spines['left'].set_bounds(ax.dataLim.ymin, ax.dataLim.ymax)
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- ax.set_ylabel('g_z_opz')
- ax.set_xlabel('svd_power')
- def svd_vs_spatcorr_lgn(df, ax=None, color='k', draw_c_inv_borders=True):
- if ax is None:
- fig, ax = plt.subplots()
- inv_df = df.query('g_z_opt<=1.96 or power_opt>0.95')
- dep_df = df.query('g_z_opt>1.96 and power_opt<=0.95')
- ax.scatter(1-inv_df['power_opt'], inv_df['g_z_opt'], color=color)
- ax.scatter(1-dep_df['power_opt'], dep_df['g_z_opt'], color=color, alpha=0.5)
- if draw_c_inv_borders:
- ax.hlines(1.96, 0.05, 0.95, linestyles='dashed', alpha=0.5)
- ax.vlines(0.05, 1.96, np.max(df['g_z_opt']), linestyles='dashed',
- alpha=0.5)
- ax.spines['left'].set_bounds(ax.dataLim.ymin, ax.dataLim.ymax)
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- ax.set_ylabel('g_z_opz')
- ax.set_xlabel('svd_power')
- def contrast_amp_distr(exc_data, inh_data, ax=None, force_align_bins=True,
- excit_col='darkorange', inhib_col='teal'):
- if ax is None:
- fig, ax = plt.subplots()
- tables = [exc_data, inh_data]
- colors = [excit_col, inhib_col]
- hists = []
- for i, (data, color) in enumerate(zip(tables, colors)):
- rmax, r0 = data.rmax.values, data.r0.values
- amp = (rmax - r0)*1000
- create_bins_with_first_hist = i == 0
- if create_bins_with_first_hist:
- if force_align_bins:
- bins = np.histogram_bin_edges(amp, bins='fd')
- bins = bins - bins[np.argmin(np.abs(bins))]
- h = np.histogram(amp, bins=bins)
- else:
- h = np.histogram(amp, bins='fd')
- split = sum(h[1] <= 0) - 1
- ax.hist(h[1][:split], h[1][:split+1], weights=h[0][:split], alpha=0.5, color=color)
- ax.hist(h[1][split:-1], h[1][split:], weights=h[0][split:], alpha=1, color=color)
- hists.append(h)
- else:
- h = np.histogram(amp, bins=hists[0][1])
- split = sum(h[1] <= 0) - 1
- ax.hist(h[1][:split], h[1][:split+1], weights=h[0][:split], alpha=0.5, color=color)
- ax.hist(h[1][split:-1], h[1][split:], weights=h[0][split:], alpha=1, color=color)
- hists.append(h)
- ax.vlines(0, 0, np.max(np.stack([h[0] for h in hists])), linestyle='dashed', alpha=0.5)
- ax.set_xlabel('Response amplitude (Hz)')
- ax.set_ylabel('N')
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- ax.spines['left'].set_bounds(ax.dataLim.ymin, ax.dataLim.ymax)
- def marginal_tuning(datdf, pars, axs=None, tuning_model='wrap_gauss'):
- if axs is None:
- gridspec_kw = {'width_ratios': [2, 1], 'height_ratios': [1, 3]}
- fig, [[ax1, delax], [ax2, ax3]] = plt.subplots(2, 2, gridspec_kw=gridspec_kw,
- tight_layout=True)
- fig.delaxes(delax)
- else:
- assert len(axs) == 3
- ax1, ax2, ax3 = axs
- # data
- datmat = datdf.pivot_table('p_spike_stim', 'grat_orientation', 'grat_contrast')
- firstrow = datmat.loc[:0, :]
- firstrow = firstrow.rename(index={0: 180.0})
- datmat = datmat.append(firstrow)
- ax2.imshow(datmat.values, origin='lower', aspect='auto')
- # smooth fit
- nfitpoints = 100
- smoothoris = np.linspace(0, 180, nfitpoints)
- smoothcons = contrast_log_scale(10, nfitpoints)
- smoothstim = np.meshgrid(smoothoris, smoothcons)
- fitmat = ori_con_2d(smoothstim, *pars, orifunc=tuning_model)
- # marginals
- # contrast marginal data points
- cons = np.unique(datdf.index.get_level_values('grat_contrast'))
- ax1.plot(np.arange(len(cons)), datmat.mean(axis=0)*1000, '.', color='k')
- # contrast marginal
- con_idcs = np.linspace(0, len(cons)-1, nfitpoints)
- ax1.plot(con_idcs, fitmat.mean(axis=0)*1000, color='k')
- # orientation marginal data points
- oris = np.unique(datmat.index.get_level_values('grat_orientation'))
- ax3.plot(datmat.mean(axis=1)*1000, np.arange(len(oris)), '.', color='k')
- # orientation marginal
- oriidcs = np.linspace(0, len(oris)-1, nfitpoints)
- ax3.plot(fitmat.mean(axis=1)*1000, oriidcs, color='k')
- # fix labels
- ax1.set_xticklabels([])
- ax1.set_ylabel('Response')
- ax3.set_yticklabels([])
- ax3.set_xlabel('Response')
- replace_imshow_ticklabels(ax2, cons, oris.astype(int))
- ax2.set_ylabel('Orientation ($^{\circ}$)')
- ax2.set_xlabel('Contrast')
- def goodness_of_fit(v1_r2s, ax=None, excit_col='darkorange', inhib_col='teal'):
- if ax is None:
- fig, ax = plt.subplots()
- h = np.histogram(v1_r2s.query('unit_type=="excit"')['r2'].values, bins='fd')
- split = sum(h[1] <= 0.4)
- ax.hist(h[1][:split], h[1][:split + 1], weights=h[0][:split], alpha=0.5, color=excit_col)
- ax.hist(h[1][split:-1], h[1][split:], weights=h[0][split:], alpha=1, color=excit_col)
- h2 = np.histogram(v1_r2s.query('unit_type=="inhib"')['r2'].values, bins=h[1])
- ax.hist(h2[1][:split], h2[1][:split+1], weights=h2[0][:split], alpha=0.5, color=inhib_col)
- ax.hist(h2[1][split:-1], h2[1][split:], weights=h2[0][split:], alpha=1, color=inhib_col)
- ax.vlines(0.4, 0, np.max(np.stack([h[0], h2[0]])), linestyles='dashed', alpha=0.5)
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- ax.spines['left'].set_bounds(ax.dataLim.ymin, ax.dataLim.ymax)
- ax.set_xlabel('Goodness of fit (r²)')
- ax.set_ylabel('N')
- def goodness_of_fit_lgn(v1_r2s, ax=None, color='k'):
- if ax is None:
- fig, ax = plt.subplots()
- h = np.histogram(v1_r2s['r2'].values, bins='fd')
- split = sum(h[1] <= 0.4)
- ax.hist(h[1][:split], h[1][:split + 1], weights=h[0][:split], alpha=0.5, color=color)
- ax.hist(h[1][split:-1], h[1][split:], weights=h[0][split:], alpha=1, color=color)
- ax.vlines(0.4, 0, np.max(np.stack([h[0]])), linestyles='dashed', alpha=0.5)
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- ax.spines['left'].set_bounds(ax.dataLim.ymin, ax.dataLim.ymax)
- ax.set_xlabel('Goodness of fit (r²)')
- ax.set_ylabel('N')
- def population_tuning(tuning_widths, ax=None, color='darkorange'):
- if ax is None:
- fig, ax = plt.subplots()
- oris = np.linspace(0, 180, 100)
- labeloris = np.linspace(-90, 90, 100)
- for tuning_width in tuning_widths:
- ax.plot(labeloris, wrapped_gaussian(oris, sigma=tuning_width), color=color, alpha=0.2)
- ax.set_xlabel('Orientation ($^{\circ}$)')
- ax.set_ylabel('Response')
- ax.spines['left'].set_bounds(ax.dataLim.ymin, ax.dataLim.ymax)
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- def population_tuning_von_mises(tuning_widths, ax=None, color='darkorange'):
- if ax is None:
- fig, ax = plt.subplots()
- oris = np.linspace(0, 180, 100)
- labeloris = np.linspace(-90, 90, 100)
- for tuning_width in tuning_widths:
- ax.plot(labeloris, von_mises(oris, kappa=tuning_width), color=color, alpha=0.2)
- ax.set_xlabel('Orientation ($^{\circ}$)')
- ax.set_ylabel('Response')
- ax.spines['left'].set_bounds(ax.dataLim.ymin, ax.dataLim.ymax)
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- def population_contrast(pardf, ax=None, color='k', alpha=0.5):
- if ax is None:
- fig, ax = plt.subplots()
- cons = np.linspace(0, 1, 100)
- for uname, pars in pardf.iterrows():
- conres = hyper_ratio(cons, 1, pars['c50'], pars['n'], 0, pars['sup'])
- conres = conres/np.max(conres)
- ax.plot(cons, conres, color=color, alpha=alpha)
- ax.set_xlabel('Contrast')
- ax.set_ylabel('Response')
- ax.spines['left'].set_bounds(ax.dataLim.ymin, ax.dataLim.ymax)
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- def osi_cumulative(osidf, ax=None, unit_type='excit', region='V1',
- excit_col='darkorange', inhib_col='teal'):
- if ax is None:
- fig, ax = plt.subplots()
- # plot OSI distribution
- osis = osidf.query(f's_region=="{region}" and unit_type=="{unit_type}"').opt_osi
- colors = {'excit': excit_col, 'inhib': inhib_col}
- ecdf = ECDF(osis)
- ax.step(ecdf.x, ecdf.y, color=colors[unit_type])
- ax.set_xlabel('Orientation selectivity index')
- ax.set_ylabel('Fraction of units')
- ax.set_xlim(0 - ax.margins()[0], 1 + ax.margins()[1])
- ax.spines['bottom'].set_bounds(0, 1)
- ax.spines['left'].set_bounds(0, 1)
- def osi_cumulative_lgn(osidf, ax=None, color='k'):
- if ax is None:
- fig, ax = plt.subplots()
- # plot OSI distribution
- osis = osidf.opt_osi
- ecdf = ECDF(osis)
- ax.step(ecdf.x, ecdf.y, color=color)
- ax.set_xlabel('Orientation selectivity index')
- ax.set_ylabel('Fraction of units')
- ax.set_xlim(0 - ax.margins()[0], 1 + ax.margins()[1])
- ax.spines['bottom'].set_bounds(0, 1)
- ax.spines['left'].set_bounds(0, 1)
- def osi_hist(osidf, ax=None, unit_type='excit', region='V1', keys=None,
- excit_col='darkorange', inhib_col='teal'):
- if ax is None:
- fig, ax = plt.subplots()
- # plot OSI distribution
- osis = osidf.query(f's_region=="{region}" and unit_type=="{unit_type}"').opt_osi
- colors = {'excit': excit_col, 'inhib': inhib_col}
- ax.hist(osis, bins='fd', color=colors[unit_type], density=True, histtype='step')
- ax.set_xlabel('Orientation selectivity index')
- ax.set_ylabel('Nunits')
- def osi_hist_lgn(osidf, ax=None, color='k'):
- if ax is None:
- fig, ax = plt.subplots()
- # plot OSI distribution
- osis = osidf.opt_osi
- ax.hist(osis, bins='fd', color=color, density=True, histtype='step')
- ax.set_xlabel('Orientation selectivity index')
- ax.set_ylabel('Nunits')
- def contrast_cumulative(pardf, ax=None, color='darkorange'):
- if ax is None:
- fig, ax = plt.subplots()
- cons = np.linspace(0, 1, 100)
- c50s = []
- for uname, pars in pardf.iterrows():
- conres = hyper_ratio(cons, 1, pars['c50'], pars['n'], 0, pars['sup'])
- conres = conres/np.max(conres)
- c50idx = np.where(conres > 0.5)[0][0]
- c50s.append(cons[c50idx])
- ecdf = ECDF(c50s)
- ax.step(ecdf.x, ecdf.y, color=color)
- ax.set_xlabel('Contrast at half-height')
- ax.set_ylabel('Fraction of units')
- ax.set_xlim(0 - ax.margins()[0], 1 + ax.margins()[1])
- ax.spines['bottom'].set_bounds(0, 1)
- ax.spines['left'].set_bounds(0, 1)
- def mean_population_contrast(pardf, ax=None, color='k'):
- if ax is None:
- fig, ax = plt.subplots()
- cons = np.linspace(0, 1, 100)
- res = []
- for uname, pars in pardf.iterrows():
- conres = hyper_ratio(cons, pars['rmax'], pars['c50'], pars['n'], pars['r0'],
- pars['sup'])
- res.append(conres)
- resmat = np.stack(res)*1000
- pop_conres = resmat.mean(axis=0)
- res_sem = sem(resmat, axis=0)
- ax.plot(cons, pop_conres, color=color)
- ax.fill_between(cons, pop_conres + res_sem, pop_conres - res_sem, color=color,
- alpha=0.5)
- ax.set_xlabel('Contrast')
- ax.set_ylabel('Response')
- ax.spines['left'].set_bounds(0, ax.dataLim.ymax)
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- _, ymax = ax.get_ylim()
- ax.set_ylim([0, ymax])
- def mean_norm_population_tuning(tuning_widths, ax=None, color='darkorange'):
- if ax is None:
- fig, ax = plt.subplots()
- oris = np.linspace(0, 180, 100)
- labeloris = np.linspace(-90, 90, 100)
- res = []
- for tw in tuning_widths:
- res.append(wrapped_gaussian(oris, sigma=tw))
- resmat = np.stack(res)
- mean_res = resmat.mean(axis=0)
- sem_res = sem(resmat, axis=0)
- ax.plot(labeloris, mean_res, color=color)
- ax.fill_between(labeloris, mean_res + sem_res, mean_res - sem_res,
- color=color, alpha=0.5)
- ax.set_xlabel('Orientation ($^{\circ}$)')
- ax.set_ylabel('Response')
- ax.spines['left'].set_bounds(0, ax.dataLim.ymax)
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- _, ymax = ax.get_ylim()
- ax.set_ylim([0, ymax])
- def mean_norm_population_tuning_von_mises(tuning_widths, ax=None, color='darkorange'):
- if ax is None:
- fig, ax = plt.subplots()
- oris = np.linspace(0, 180, 100)
- labeloris = np.linspace(-90, 90, 100)
- res = []
- for tw in tuning_widths:
- res.append(von_mises(oris, kappa=tw))
- resmat = np.stack(res)
- mean_res = resmat.mean(axis=0)
- sem_res = sem(resmat, axis=0)
- ax.plot(labeloris, mean_res, color=color)
- ax.fill_between(labeloris, mean_res + sem_res, mean_res - sem_res,
- color=color, alpha=0.5)
- ax.set_xlabel('Orientation ($^{\circ}$)')
- ax.set_ylabel('Response')
- ax.spines['left'].set_bounds(0, ax.dataLim.ymax)
- ax.spines['bottom'].set_bounds(ax.dataLim.xmin, ax.dataLim.xmax)
- _, ymax = ax.get_ylim()
- ax.set_ylim([0, ymax])
|