"""Figure 4 and some 4S1 plots, use run -i fig4.py""" mvimeasures = ['meanrate', 'meanrate02', 'meanrate35', 'blankmeanrate', 'meanburstratio', 'blankmeanburstratio'] grtmeasures = ['meanrate', 'meanrate', 'meanrate', 'blankmeanrate', 'meanburstratio', 'blankmeanburstratio'] mi = pd.MultiIndex.from_product([mvigrtmsustrs, STIMTYPES, [False, 'prestim', 'cond']], names=['msu', 'stimtype', 'blank']) fig4 = pd.DataFrame(index=mi, columns=['meanrate', 'meanburstratio']) ## NOTE: make sure that rows are not overwritten due to temporarily enabling iteration ## over st8 in any of the following loops! # strip, scatter and dumbbell plot movie vs grating FMI for applicable measures: np.random.seed(0) # to get identical horizontal jitter in strip plots on every run figsize = DEFAULTFIGURESIZE linmin, linmax, linstep = -1, 1, 1 ticks = np.arange(linmin, linmax+linstep, linstep) for mvimeasure, grtmeasure in zip(mvimeasures, grtmeasures): measure = mvimeasure isblank = mvimeasure.startswith('blank') if isblank: measure = mvimeasure.split('blank')[1] axislabel = measure2axislabel[mvimeasure] axislabel = short2longaxislabel.get(axislabel, axislabel) if axislabel[0].islower(): Axislabel = axislabel.capitalize() else: Axislabel = axislabel for st8 in ['none']:#ALLST8S: #mvifmis, grtfmis = [], [] mvimaxfmis, grtmaxfmis, grtmaxfmi2s = [], [], [] exmplis, exmplmsustrs, normlis = [], [], [] # collect all movie FMIs: ''' for mseustr in mvimseustrs: mvifmi = mviFMI[mvimeasure][mseustr, st8] if pd.isna(mvifmi): continue mvifmis.append(mvifmi) # collect all grating FMIs: for mseustr in grtmseustrs: grtfmi = grtFMI[grtmeasure][mseustr, st8] if pd.isna(grtfmi): continue grtfmis.append(grtfmi) ''' # collect paired movie and grating max FMIs: keptmsui = 0 for msustr in mvigrtmsustrs: mvimaxfmi = maxFMI[mvimeasure][msustr, st8, 'mvi'] grtmaxfmi = maxFMI[grtmeasure][msustr, st8, 'grt'] ''' ## hack to replicate Steffen's code in R: if mvimeasure == 'meanrate': othermvimaxfmi = maxFMI['meanburstratio'][msustr, st8, 'mvi'] othergrtmaxfmi = maxFMI['meanburstratio'][msustr, st8, 'grt'] if pd.isna(othermvimaxfmi) or pd.isna(othergrtmaxfmi): continue ''' if pd.isna(mvimaxfmi) or pd.isna(grtmaxfmi): # missing one or both maxFMI values continue if isblank: # add a second grtmaxfmi measure for blank cond blankname = 'blankcond' + measure grtmaxfmi2 = maxFMI[blankname][msustr, st8, 'grt'] if pd.isna(grtmaxfmi2): continue else: grtmaxfmi2s.append(grtmaxfmi2) mvimaxfmis.append(mvimaxfmi) grtmaxfmis.append(grtmaxfmi) if measure in fig4.columns: assert mvimeasure == grtmeasure if isblank: # save both kinds of grt blank measures fig4.loc[msustr, 'mvi', 'prestim'][measure] = mvimaxfmi # save fig4.loc[msustr, 'grt', 'prestim'][measure] = grtmaxfmi # save fig4.loc[msustr, 'grt', 'cond'][measure] = grtmaxfmi2 # save else: fig4.loc[msustr, 'mvi', False][measure] = mvimaxfmi # save fig4.loc[msustr, 'grt', False][measure] = grtmaxfmi # save #if grtmeasure == 'meanburstratio' and grtmaxfmi > 0.8: # print('OUTLIER: %s grtmaxfmi=%g' % (msustr, grtmaxfmi)) if msustr in msu2exmpli: exmplis.append(keptmsui) exmplmsustrs.append(msustr) else: normlis.append(keptmsui) keptmsui += 1 # manually increment #mvifmis = np.asarray(mvifmis) #grtfmis = np.asarray(grtfmis) mvimaxfmis = np.asarray(mvimaxfmis) grtmaxfmis = np.asarray(grtmaxfmis) grtmaxfmi2s = np.asarray(grtmaxfmi2s) assert len(mvimaxfmis) == len(grtmaxfmis) npairs = len(mvimaxfmis) ''' ## strip plot movie and grating FMIs, for all mseus: f, a = plt.subplots(figsize=figsize) wintitle('FMI %s nat movie grating stripplot %s' % (mvimeasure, st8)) # plot y=0 line: a.axhline(y=0, ls='--', marker='', color='lightgray', zorder=-np.inf) data = pd.DataFrame(data={'stimtype':['Movie']*len(mvifmis)+['Grating']*len(grtfmis), 'FMI':np.concatenate([mvifmis, grtfmis])}) sns.stripplot(x='stimtype', y='FMI', data=data, jitter=True, clip_on=False, marker='.', color='None', edgecolor=st82clr[st8], size=np.sqrt(50)) # exclude extreme +/- 1 FMI values from mean and ttest: #mvifmisnon1 = mvifmis[abs(mvifmis) != 1] #grtfmisnon1 = grtfmis[abs(grtfmis) != 1] # plot mean with short horizontal lines: #meanmvifmi, meangrtfmi = mvifmisnon1.mean(), grtfmisnon1.mean() #a.plot([-0.25, 0.25], [meanmvifmi, meanmvifmi], '-', lw=2, c='red', zorder=np.inf) #a.plot([0.75, 1.25], [meangrtfmi, meangrtfmi], '-', lw=2, c='red', zorder=np.inf) a.set_xlabel('') a.set_ylabel('%s FMI' % Axislabel) a.set_ylim(-1, 1) t, p = ttest_ind(mvifmisnon1, grtfmisnon1, equal_var=False) # non-paired t-test a.add_artist(AnchoredText('p$=$%.2g' % p, loc='upper center', frameon=False)) # connect the dots: x = np.array([[0]*npairs, [1]*npairs]) y = np.array([mvimaxfmis, grtmaxfmis]) a.plot(x, y, '-', c='k', alpha=0.2, lw=1) # due to jitter, dots don't perfectly connect. Can get actual data using: #mvixy, grtxy = a.collections[0].get_offsets(), a.collections[1].get_offsets() # but some of those points aren't paired, which makes it complicated ''' ## strip plot paired movie and grating max FMIs: if mvimeasure == 'meanrate': # 2 column wide strip plot f, a = plt.subplots(figsize=(figsize[0]*1.35, figsize[1]*1.5)) elif mvimeasure == 'blankmeanrate': # 3 column wide strip plot f, a = plt.subplots(figsize=(figsize[0]*1.9, figsize[1]*1.5)) elif mvimeasure == 'blankmeanburstratio': # 3 column normal width strip plot f, a = plt.subplots(figsize=(figsize[0]*1.4, figsize[1])) else: f, a = plt.subplots(figsize=figsize) wintitle('maxFMI %s movie grating stripplot' % mvimeasure) # plot y=0 line: a.axhline(y=0, ls='--', marker='', color='lightgray', zorder=-np.inf) datad = {'Movie':mvimaxfmis, 'Grating':grtmaxfmis} if isblank: datad = {'Movie':mvimaxfmis, 'Grating':grtmaxfmis, 'GratingCond':grtmaxfmi2s} data = pd.DataFrame.from_dict(datad, orient='index').transpose() sns.stripplot(ax=a, data=data, clip_on=False, marker='.', color='None', edgecolor='black', size=np.sqrt(50)) # get fname of appropriate LMM .cvs file: if mvimeasure == 'meanrate' and grtmeasure == 'meanrate': fname = os.path.join(PAPERPATH, 'stats', 'figure_4a_pred_means.csv') elif mvimeasure == 'blankmeanrate' and grtmeasure == 'blankmeanrate': fname = os.path.join(PAPERPATH, 'stats', 'figure_4b_pred_means.csv') elif mvimeasure == 'meanburstratio' and grtmeasure == 'meanburstratio': fname = os.path.join(PAPERPATH, 'stats', 'figure_4_S1e_pred_means.csv') elif mvimeasure == 'blankmeanburstratio' and grtmeasure == 'blankmeanburstratio': fname = os.path.join(PAPERPATH, 'stats', 'figure_4_S1f_pred_means.csv') else: print("WARNING: No LMM stats for (mvimeasure=%s, grtmeasure=%s)" % (mvimeasure, grtmeasure)) fname = None if fname: try: df = pd.read_csv(fname) foundregression = True except FileNotFoundError: print('Missing file: %s' % fname) foundregression = False if foundregression: # fetch LMM means from .csv: meanmvimaxfmi = df['mvi'][0] meangrtmaxfmi = df['grt'][0] # plot mean with short horizontal lines: a.plot([-0.25, 0.25], [meanmvimaxfmi, meanmvimaxfmi], '-', lw=2, c='red', zorder=np.inf) a.plot([0.75, 1.25], [meangrtmaxfmi, meangrtmaxfmi], '-', lw=2, c='red', zorder=np.inf) if isblank: meangrtmaxfmi2 = df['grt0c'][0] a.plot([1.75, 2.25], [meangrtmaxfmi2, meangrtmaxfmi2], '-', lw=2, c='red', zorder=np.inf) a.set_ylabel('%s FMI' % Axislabel) #if measure.startswith('meanrate'): # a.set_ylim(-0.6, 1) # a.set_yticks([-0.5, 0, 0.5, 1]) #else: a.set_ylim(-1, 1) a.set_yticks([-1, -0.5, 0, 0.5, 1]) a.spines['bottom'].set_position(('outward', 5)) a.spines['bottom'].set_visible(False) a.tick_params(bottom=False) # connect the dots: if isblank: x = np.array([[0]*npairs, [1]*npairs, [2]*npairs]) y = np.array([mvimaxfmis, grtmaxfmis, grtmaxfmi2s]) else: x = np.array([[0]*npairs, [1]*npairs]) y = np.array([mvimaxfmis, grtmaxfmis]) signs = np.sign(y) nonsignchangeis = signs[0] == signs[1] posslopeis = (signs[0] < 0) & (signs[1] > 0) negslopeis = (signs[0] > 0) & (signs[1] < 0) #signchangeis = signs[0] != signs[1] a.plot(x[:, nonsignchangeis], y[:, nonsignchangeis], '-', c='k', alpha=0.2, lw=1) a.plot(x[:, posslopeis], y[:, posslopeis], '--', c='k', alpha=1.0, lw=1) a.plot(x[:, negslopeis], y[:, negslopeis], '-', c='k', alpha=1.0, lw=1) #a.plot(x[:, signchangeis], y[:, signchangeis], '-', c='k', alpha=1.0, lw=1) # due to jitter, dots don't perfectly connect. Can get actual data using: #mvixy, grtxy = a.collections[0].get_offsets(), a.collections[1].get_offsets() ## scatter plot movie vs. grating max FMIs: ''' f, a = plt.subplots(figsize=figsize) wintitle('maxFMI %s movie grating scatter' % mvimeasure) # plot x=0 and y=0 lines: a.axhline(y=0, ls='--', marker='', color='lightgray', zorder=-np.inf) a.axvline(x=0, ls='--', marker='', color='lightgray', zorder=-np.inf) # plot y=x line: xyline = [linmin, linmax], [linmin, linmax] a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1) # plot normal (non-example) points: a.scatter(grtmaxfmis[normlis], mvimaxfmis[normlis], clip_on=False, marker='.', c='None', edgecolor=st82clr[st8], s=DEFSZ) # plot example points, one at a time: for exmpli, msustr in zip(exmplis, exmplmsustrs): marker = exmpli2mrk[msu2exmpli[msustr]] c = exmpli2clr[msu2exmpli[msustr]] sz = exmpli2sz[msu2exmpli[msustr]] lw = exmpli2lw[msu2exmpli[msustr]] a.scatter(grtmaxfmis[exmpli], mvimaxfmis[exmpli], marker=marker, c=c, s=sz, lw=lw) # exclude extreme +/- 1 FMI values from mean and ttest: non1is = (abs(grtmaxfmis) != 1) & (abs(mvimaxfmis) != 1) grtmaxfmisnon1 = grtmaxfmis[non1is] mvimaxfmisnon1 = mvimaxfmis[non1is] # plot mean: a.scatter(np.mean(grtmaxfmisnon1), np.mean(mvimaxfmisnon1), c='red', edgecolor='red', s=50, marker='^') a.set_xlabel('Grating %s FMI' % axislabel) a.set_ylabel('Movie %s FMI' % axislabel) a.set_xlim(linmin, linmax) a.set_ylim(linmin, linmax) a.set_xticks(ticks) a.set_yticks(a.get_xticks()) # make log scale y ticks the same as x ticks a.minorticks_off() a.set_aspect('equal') a.spines['left'].set_position(('outward', 4)) a.spines['bottom'].set_position(('outward', 4)) t, p = ttest_rel(grtmaxfmisnon1, mvimaxfmisnon1) # paired t-test a.add_artist(AnchoredText('p$=$%.2g' % p, loc='lower right', frameon=False)) ''' ## dumbbell plot: ''' f, a = plt.subplots(figsize=DUMBBELLFIGSIZE) wintitle('maxFMI %s movie grating dumbbell' % mvimeasure) # plot x=0 line: a.axvline(x=0, ls='--', marker='', color='lightgray', zorder=-np.inf) # plot horizontal lines: mvimaxfmisortis = mvimaxfmis.argsort() # y vals for hlines npairs = len(mvimaxfmis) ys = np.arange(npairs) xmvis, xgrts = mvimaxfmis[mvimaxfmisortis], grtmaxfmis[mvimaxfmisortis] a.hlines(ys, xmvis, xgrts, zorder=-100) sz = 100 # plot grt points: a.scatter(xgrts, ys, clip_on=False, marker='.', c='white', edgecolor=st82clr[st8], s=sz) # plot mvi points: a.scatter(xmvis, ys, clip_on=False, marker='.', c=st82clr[st8], s=sz) a.set_xlabel('%s FMI' % Axislabel) a.set_ylabel('Neurons') a.set_xlim(linmin, linmax) a.set_ylim(-1, npairs) a.set_xticks(ticks) a.set_yticks([]) a.spines['left'].set_position(('outward', 4)) a.spines['left'].set_visible(False) ''' ''' # plot CDFs of spatial suppression index for blankscreen movies/gratings wrt full screen # movies/gratings, for meanrate and meanburstratio, for control and opto conditions: figsize = DEFAULTFIGURESIZE stimtype2resp = {'mvi':mviresp, 'grt':grtresp} for stimtype in ['mvi', 'grt']: resp = stimtype2resp[stimtype] if stimtype == 'mvi': resp = resp.xs('nat', level='kind') # dereference movie 'kind' index level for measure in ['meanrate', 'meanburstratio']: f, a = plt.subplots(figsize=figsize) wintitle('SSI %s %s blank vs fullscreen CDF' % (stimtype, measure)) opto2SSI = {} for opto in OPTOS: rows = resp.xs(['none', opto], level=['st8', 'opto']) # only mseu index left fullscreen = rows[measure] blank = rows['blank'+measure] SSI = (blank - fullscreen) / (blank + fullscreen) SSI = np.float64(SSI[SSI.notna()].values) # pull float array out of object Series opto2SSI[opto] = SSI SSIbins = list(np.unique(SSI)) + [10] fb = opto2fb[opto].capitalize() a.hist(SSI, bins=SSIbins, density=True, histtype='step', cumulative=True, clip_on=True, lw=1.5, label=fb, color=opto2clr[opto], alpha=1) a.set_xlabel('Spatial suppression index') a.set_ylabel('Cumulative probability') #a.legend(frameon=False) a.set_xlim(-1, 1) a.set_ylim(0, 1.01) a.set_yticks([0, 0.5, 1]) #a.spines['left'].set_position(('outward', 4)) _, KS_p = ks_2samp(opto2SSI[False], opto2SSI[True]) txt = '$\mathregular{p_{KS}=%.2g}$' % KS_p # prob that distribs are the same a.add_artist(AnchoredText(txt, loc='lower right', frameon=False)) # stripplot spatial suppression index for blankscreen movies/gratings wrt full screen # movies/gratings, for meanrate and meanburstratio, for both opto conditions, for all mseu: figsize = DEFAULTFIGURESIZE stimtype2resp = {'mvi':mviresp, 'grt':grtresp} for measure in ['meanrate', 'meanburstratio']: opto2SSI = {} for stimtype in ['mvi', 'grt']: resp = stimtype2resp[stimtype] if stimtype == 'mvi': resp = resp.xs('nat', level='kind') # dereference movie 'kind' index level for opto in OPTOS: rows = resp.xs(['none', opto], level=['st8', 'opto']) # only mseu index left fullscreen = rows[measure] blank = rows['blank'+measure] SSI = (blank - fullscreen) / (blank + fullscreen) #SSI = (blank - fullscreen) / blank SSI = np.float64(SSI[SSI.notna()].values) # pull float array out of object Series opto2SSI[opto] = SSI # stripplot: SSIons, SSIoffs = opto2SSI[True], opto2SSI[False] f, a = plt.subplots(figsize=figsize) wintitle('SSI %s %s blank vs fullscreen stripplot' % (stimtype, measure)) data = pd.DataFrame.from_dict({'Feedback':SSIoffs, 'Suppression':SSIons}, orient='index').transpose() sns.stripplot(ax=a, data=data, clip_on=False, marker='.', color='None', edgecolor='black', size=np.sqrt(50)) # exclude extreme +/- 1 SSI values from mean: SSIonsnon1 = SSIons[abs(SSIons) != 1] SSIoffsnon1 = SSIoffs[abs(SSIoffs) != 1] # plot mean with short horizontal lines: meanSSIon, meanSSIoff = SSIonsnon1.mean(), SSIoffsnon1.mean() a.plot([-0.25, 0.25], [meanSSIoff, meanSSIoff], '-', lw=2, c='red', zorder=np.inf) a.plot([0.75, 1.25], [meanSSIon, meanSSIon], '-', lw=2, c='red', zorder=np.inf) a.set_ylabel('Spatial suppression index') a.set_ylim(-1, 1) a.spines['bottom'].set_position(('outward', 5)) a.spines['bottom'].set_visible(False) a.tick_params(bottom=False) # stripplot FMI spatial suppression index for blankscreen movies/gratings wrt full screen # movies/gratings, for meanrate and meanburstratio, for all mseu: figsize = DEFAULTFIGURESIZE stimtype2FMI = {'mvi':mviFMI, 'grt':grtFMI} for measure in ['meanrate', 'meanburstratio']: stimtype2SSI = {} for stimtype in ['mvi', 'grt']: FMI = stimtype2FMI[stimtype] rows = FMI.xs('none', level='st8') # only mseu index left fullscreen = rows[measure] blank = rows['blank'+measure] SSI = (blank - fullscreen) / (abs(blank) + abs(fullscreen)) #SSI = (blank - fullscreen) / blank SSI = np.float64(SSI[SSI.notna()].values) # pull float array out of object Series stimtype2SSI[stimtype] = SSI # plot CDF: f, a = plt.subplots(figsize=figsize) wintitle('SSI %s %s FMI blank vs fullscreen' % (stimtype, measure)) SSIbins = list(np.unique(SSI)) + [10] a.hist(SSI, bins=SSIbins, density=True, histtype='step', cumulative=True, clip_on=True, lw=1.5, color='black', alpha=1) a.set_xlabel('FMI spatial suppression index') a.set_ylabel('Cumulative probability') #a.legend(frameon=False) a.set_xlim(-1, 1) a.set_ylim(0, 1.01) a.set_yticks([0, 0.5, 1]) #a.spines['left'].set_position(('outward', 4)) # stripplot: mviSSI, grtSSI = stimtype2SSI['mvi'], stimtype2SSI['grt'] f, a = plt.subplots(figsize=figsize) wintitle('SSI %s FMI blank vs fullscreen stripplot' % measure) data = pd.DataFrame.from_dict({'Movie':mviSSI, 'Grating':grtSSI}, orient='index').transpose() sns.stripplot(ax=a, data=data, clip_on=False, marker='.', color='None', edgecolor='black', size=np.sqrt(50)) # exclude extreme +/- 1 SSI values from mean: mviSSInon1 = mviSSI[abs(mviSSI) != 1] grtSSInon1 = grtSSI[abs(grtSSI) != 1] # plot mean with short horizontal lines: meanmvifmi, meangrtfmi = mviSSInon1.mean(), grtSSInon1.mean() a.plot([-0.25, 0.25], [meanmvifmi, meanmvifmi], '-', lw=2, c='red', zorder=np.inf) a.plot([0.75, 1.25], [meangrtfmi, meangrtfmi], '-', lw=2, c='red', zorder=np.inf) a.set_ylabel('FMI spatial suppression index') a.set_ylim(-1, 1) a.spines['bottom'].set_position(('outward', 5)) a.spines['bottom'].set_visible(False) a.tick_params(bottom=False) # dumbbell plot FMI spatial suppression index for blankscreen movies/gratings wrt full screen # movies/gratings, for meanrate and meanburstratio, for all mseu: figsize = DEFAULTFIGURESIZE for measure in ['meanrate', 'meanburstratio']: stimtype2SSI = {} for stimtype in ['mvi', 'grt']: rows = maxFMI.xs(['none', stimtype], level=['st8', 'stimtype']) # only msu index left fullscreen = rows[measure] blank = rows['blank'+measure] SSI = (blank - fullscreen) / (abs(blank) + abs(fullscreen)) #SSI = (blank - fullscreen) / blank SSI = np.float64(SSI.values) # pull float array out of object Series stimtype2SSI[stimtype] = SSI mviSSI, grtSSI = stimtype2SSI['mvi'], stimtype2SSI['grt'] keepis = pd.notna(mviSSI) & pd.notna(grtSSI) # remove any unit that has NaN in either stim mviSSI, grtSSI = mviSSI[keepis], grtSSI[keepis] f, a = plt.subplots(figsize=figsize) wintitle('SSI %s maxFMI blank vs fullscreen stripplot dumbbell' % measure) # plot x=0 line: a.axvline(x=0, ls='--', marker='', color='lightgray', zorder=-np.inf) # plot horizontal lines: mviSSIsortis = mviSSI.argsort() # y vals for hlines npairs = len(mviSSI) ys = np.arange(npairs) xmvis, xgrts = mviSSI[mviSSIsortis], grtSSI[mviSSIsortis] a.hlines(ys, xmvis, xgrts, zorder=-100) sz = 100 # plot grt points: a.scatter(xgrts, ys, marker='.', c='white', edgecolor=st82clr[st8], s=sz) # plot mvi points: a.scatter(xmvis, ys, marker='.', c=st82clr[st8], s=sz) axislabel = measure2axislabel[measure] if axislabel[0].islower(): Axislabel = axislabel.capitalize() else: Axislabel = axislabel a.set_xlabel('%s FMI SSI' % Axislabel) a.set_ylabel('Neurons') #a.set_xlim(linmin-eps, linmax+eps) a.set_ylim(-1, npairs) #a.set_xticks(ticks) a.set_yticks([]) '''