fig5S2.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. """Figure 5S2 pupil area plots, use run -i fig5S2.py"""
  2. ## collect PSTH trial matrices with same timebase as pupil area signal, masked by runspeed
  3. ## to include only sitting periods, then also masked by pupil constriction/dilation upper and
  4. ## lower quartiles. Store in arearate_mviresp DataFrame indexed by [mseu, opto]
  5. allmseustrs = mviresp.index.levels[0].values # get all mice, series, experiments, units
  6. levels = [allmseustrs, OPTOS]
  7. names = ['mseu', 'opto']
  8. mi = pd.MultiIndex.from_product(levels, names=names)
  9. columns = ['trialmat', 'bins', 'binw', 'tq_trialmat', 'bq_trialmat',
  10. 'psth', 'tq_psth', 'bq_psth', 'pct_changes']
  11. arearate_mviresp = pd.DataFrame(index=mi, columns=columns)
  12. arearates = {} # mse to (arearate, arearate_ts) mapping
  13. # for each row (mse) in ipos_opto df, find 1st derivative of pupil area trial matrix:
  14. for index, row in ipos_opto.iterrows():
  15. msestr, stimtype, opto = index
  16. if not stimtype == 'mvi':
  17. continue
  18. print(msestr, stimtype, opto)
  19. DX = 1 # decimation factor, e.g. 5 increases sampling period by 5X, from ~20 ms to ~100 ms
  20. area_trialmat = row['area_trialmat'][:, ::DX]
  21. area_trialts = row['area_trialts'][::DX]
  22. ntrials, nt = area_trialmat.shape
  23. arearate = np.diff(area_trialmat, axis=1) # 2D: ntrials, nt-1
  24. arearate_ts = area_trialts[:-1] # drop the last timepoint due to diff
  25. arearates[msestr] = arearate.copy(), arearate_ts.copy()
  26. # get locomotion info and mask out all instances of running:
  27. runrow = runspeed.loc[msestr, 'nat', opto]
  28. assert (row['trialis'] == runrow['trialis']).all() # sanity check
  29. run_ts, speed = runrow['t'], runrow['speed']
  30. # each runspeed trial can have slightly different number of timepoints, so have to
  31. # resample each runspeed trial separately:
  32. assert len(speed) == ntrials
  33. for i in range(ntrials): # iterate over trials
  34. f = scipy.interpolate.interp1d(run_ts[i], speed[i], axis=-1, kind='linear',
  35. fill_value='extrapolate')
  36. rs_speed = f(arearate_ts) # runspeed signal resampled to arearate_ts
  37. ## TODO: maybe apply continuous_runs() here to further smooth out running periods
  38. # mask out arearate during running periods:
  39. runmask = rs_speed > 0.25 # cm/s
  40. arearate[i, runmask] = np.nan # these points shouldn't influence the percentile calc
  41. # get top and bottom quartiles for each timepoint, averaged across all trials:
  42. tq, bq = np.nanpercentile(arearate, [75, 25], axis=0) # each is nt-1
  43. assert len(tq) == nt - 1
  44. assert len(bq) == nt - 1
  45. # mask out timepoints per trial in which arearate falls in top or bottom quartile:
  46. tqmask = np.int8(arearate >= tq) # 2D binary: ntrials, nt-1
  47. bqmask = np.int8(arearate <= bq)
  48. # create top and bottom quartile arearate arrays:
  49. arearatetq = np.full(arearate.shape, np.nan)
  50. arearatetq[tqmask] = arearate[tqmask]
  51. arearatebq = np.full(arearate.shape, np.nan)
  52. arearatebq[bqmask] = arearate[bqmask]
  53. # get all mseu for this mse:
  54. hits = findmse(allmseustrs, msestr)
  55. mseustrs = allmseustrs[hits] # all mseu that belong to this mse
  56. # get bins for calculating PSTHs using arearate timepoints:
  57. binw = np.median(np.diff(arearate_ts))
  58. ledges = arearate_ts # left edges
  59. redges = np.hstack([arearate_ts[1:], arearate_ts[-1]+binw]) # right edges
  60. bins = np.column_stack((ledges, redges))
  61. # calculate PSTHs and binned % rate change for each rate percentile range for each mseu:
  62. for mseustr in mseustrs:
  63. trialmat = np.full(arearate.shape, np.nan)
  64. mviresprow = mviresp.loc[mseustr, 'nat', 'none', opto]
  65. if np.isnan(mviresprow['dt']) or mviresprow['snr'] < SNRTHRESH:
  66. continue
  67. #raster, braster = mviresprow['raster'], mviresprow['braster']
  68. raster = mviresprow['raster']
  69. # generate trial-based psth matrix, binned at bins:
  70. for triali, trspkts in enumerate(raster):
  71. # tres is ignored when kernel == None
  72. trpsth = raster2psth([trspkts], bins, binw, None, kernel=None)
  73. trialmat[triali] = trpsth
  74. # create top quartile trialmat by masking out all entries in trialmat which are not
  75. # in top quartile:
  76. tq_trialmat = trialmat.copy()
  77. tq_trialmat[tqmask == 0] = np.nan
  78. # create bottom quartile trialmat by masking out all entries in trialmat which are not
  79. # in bottom quartile:
  80. bq_trialmat = trialmat.copy()
  81. bq_trialmat[bqmask == 0] = np.nan
  82. # compute mean across trials, only timepoints remain:
  83. psth = np.nanmean(trialmat, axis=0)
  84. tq_psth = np.nanmean(tq_trialmat, axis=0)
  85. bq_psth = np.nanmean(bq_trialmat, axis=0)
  86. # get firing rate percentile threshold ranges of the psth:
  87. lo, bq, mid, tq, hi = np.percentile(psth, [0, 25, 50, 75, 100])
  88. rpctileranges = [[lo, bq], [bq, mid], [mid, tq], [tq, hi]]
  89. # calculate binned percent change of PSTH of top quartile vs bottom quartile pupil
  90. # arearate, for each firing rate percentile range:
  91. pct_changes = []
  92. for rpctilerange in rpctileranges:
  93. # find PSTH timepoints that fall in this rate percentile range:
  94. tis = (rpctilerange[0] < psth) & (psth <= rpctilerange[1]) # bool array
  95. if (tis == False).all(): # no timepoints in this rpctilerange
  96. pct_change = np.nan
  97. else:
  98. tqmean = tq_psth[tis].mean()
  99. bqmean = bq_psth[tis].mean()
  100. if bqmean > 0:
  101. pct_change = (tqmean - bqmean) / bqmean * 100
  102. else:
  103. #print('bqmean', bqmean)
  104. pct_change = np.nan
  105. pct_changes.append(pct_change)
  106. pct_changes = np.array(pct_changes)
  107. arearate_mviresprow = arearate_mviresp.loc[mseustr, opto]
  108. arearate_mviresprow['trialmat'] = trialmat
  109. arearate_mviresprow['tq_trialmat'] = tq_trialmat
  110. arearate_mviresprow['bq_trialmat'] = bq_trialmat
  111. arearate_mviresprow['bins'] = bins
  112. arearate_mviresprow['binw'] = binw
  113. arearate_mviresprow['psth'] = psth
  114. arearate_mviresprow['tq_psth'] = tq_psth
  115. arearate_mviresprow['bq_psth'] = bq_psth
  116. arearate_mviresprow['pct_changes'] = pct_changes # length 4, 1 value per FR quartile
  117. ## collect % change values for both opto conditions, and resample them to allow
  118. ## confidence interval calculations; keep only rows that have non-nan entries in pct_changes:
  119. arearate_mviresp_notna = arearate_mviresp.dropna(subset=['pct_changes'])
  120. pcoffs = np.vstack(arearate_mviresp_notna.loc[(slice(None), False), 'pct_changes'].values)
  121. pcons = np.vstack(arearate_mviresp_notna.loc[(slice(None), True), 'pct_changes'].values)
  122. noffs, nons = len(pcoffs), len(pcons) # not necessarily the same, some can be unpaired
  123. NSAMPLES = 5000
  124. rspcoffmeds = np.full((NSAMPLES, 4), np.nan) # resampled % change opto off medians
  125. rspconmeds = np.full((NSAMPLES, 4), np.nan)
  126. rng = np.random.default_rng(0) # init random number generator with seed 0
  127. for samplei in range(NSAMPLES):
  128. rspcoffs = rng.choice(pcoffs, noffs, replace=True, axis=0)
  129. rspcons = rng.choice(pcons, nons, replace=True, axis=0)
  130. rspcoffmeds[samplei] = np.nanmedian(rspcoffs, axis=0)
  131. rspconmeds[samplei] = np.nanmedian(rspcons, axis=0)
  132. # calculate medians and percentiles for CIs:
  133. med_pcoffs = np.nanmedian(pcoffs, axis=0)
  134. med_rspcoffmeds = np.nanmedian(rspcoffmeds, axis=0)
  135. lci_rspcoffmeds = np.nanpercentile(rspcoffmeds, 2.5, axis=0)
  136. uci_rspcoffmeds = np.nanpercentile(rspcoffmeds, 97.5, axis=0)
  137. med_pcons = np.nanmedian(pcons, axis=0)
  138. med_rspconmeds = np.nanmedian(rspconmeds, axis=0)
  139. lci_rspconmeds = np.nanpercentile(rspconmeds, 2.5, axis=0)
  140. uci_rspconmeds = np.nanpercentile(rspconmeds, 97.5, axis=0)
  141. print('median pcoffs: ', med_pcoffs)
  142. print('median rspcoffmeds:', med_rspcoffmeds)
  143. print(' 2.5% rspcoffmeds:', lci_rspcoffmeds)
  144. print(' 97.5% rspcoffmeds:', uci_rspcoffmeds)
  145. print('median pcons: ', med_pcons)
  146. print('median rspconmeds: ', med_rspconmeds)
  147. print(' 2.5% rspconmeds: ', lci_rspconmeds)
  148. print(' 97.5% rspconmeds: ', uci_rspconmeds)
  149. ## plot arearate trial matrix for example experiment:
  150. exmplmsestrs = ['PVCre_2017_0006_s03_e03',
  151. 'PVCre_2017_0015_s07_e04',
  152. 'PVCre_2019_0002_s08_e04']
  153. for msestr in exmplmsestrs:#list(arearates):
  154. arearate, arearate_ts = arearates[msestr]
  155. binw = np.median(np.diff(arearate_ts)) # s
  156. arearate = arearate / binw # normalized pupil area per sec
  157. ntrials = len(arearate)
  158. tmin, tmax = arearate_ts[0], np.ceil(arearate_ts[-1])
  159. extent = tmin, tmax, ntrials, 1
  160. f, a = plt.subplots(figsize=(6, 3))
  161. wintitle('arearate trialmat %s' % msestr)
  162. #std = np.nanstd(arearate)
  163. #vlim = 3*std
  164. vlim = 0.3 # might result in a bit of clipping of outlier values
  165. im = a.imshow(arearate, extent=extent, aspect='auto', origin='upper', cmap='seismic',
  166. interpolation='nearest', vmin=-vlim, vmax=vlim)
  167. plt.colorbar(im, ticks=[-vlim, 0, vlim])
  168. #a.set_xticks(np.arange(5))
  169. a.set_xlabel('Time (s)')
  170. a.set_ylabel('Trial')
  171. #a.set_xticks(tmin, tmax, 50)
  172. yticks = np.arange(0, ntrials+1, 50)
  173. yticks[0] = 1
  174. a.set_yticks(yticks)
  175. ## plot example raster plot:
  176. exmplmseustr = 'PVCre_2019_0002_s08_e04_u32'
  177. mviresprow = mviresp.loc[exmplmseustr, 'nat', 'none', False]
  178. raster = mviresprow['raster']
  179. dt = mviresprow['dt'] # stimulus duration (s)
  180. SCATTER = False # True: low quality, but fast; False: high quality, but slow
  181. title = 'movie raster %s %s' % (mseustr, False)
  182. a = simpletraster(raster=raster, alpha=0.5, s=1, dt=dt, offsets=[0, 0],
  183. scatter=SCATTER,
  184. title=title, inchespersec=1.5*RASTERSCALEX,
  185. inchespertrial=1/50*RASTERSCALEX,
  186. xaxis=True)
  187. a.spines['left'].set_position(('outward', 4))
  188. a.spines['bottom'].set_position(('outward', 4))
  189. yticks = np.arange(0, ntrials+1, 50)
  190. yticks[0] = 1
  191. a.set_yticks(yticks)
  192. ## plot example PSTHs:
  193. exmplmsestr = 'PVCre_2019_0002_s08_e04'
  194. hits = findmse(allmseustrs, exmplmsestr)
  195. exmplmseustrs = allmseustrs[hits]
  196. alpha = 0.5
  197. for mseustr in [exmplmseustr]:#exmplmseustrs:
  198. psthoptos = arearate_mviresp.loc[mseustr][['tq_psth', 'bq_psth']]
  199. #maxpsth = np.vstack(psthoptos.values).max() # max of mean PSTH across both opto conditions
  200. maxpsth = np.hstack(psthoptos.values.flatten()).max()
  201. for opto in OPTOS:
  202. row = arearate_mviresp.loc[(mseustr, opto)]
  203. bins, psth, tq_psth, bq_psth = row[['bins', 'psth', 'tq_psth', 'bq_psth']]
  204. if np.any(np.isnan(bins)):
  205. continue
  206. t = bins.mean(axis=1)
  207. f, a = plt.subplots(figsize=(5, 3))
  208. wintitle('top bottom qrt PSTH %s opto=%s' % (mseustr, opto))
  209. #maxpsth = psth.max()
  210. #a.plot(t, psth/maxpsth, '-', color='black', alpha=alpha, label='Mean')
  211. a.plot(t, tq_psth, '-', color='red', alpha=alpha, label='Top quartile')
  212. a.plot(t, bq_psth, '-', color='blue', alpha=alpha, label='Bottom quartile')
  213. a.spines['left'].set_position(('outward', 4))
  214. a.spines['bottom'].set_position(('outward', 4))
  215. a.set_xlabel('Time (s)')
  216. a.set_ylabel('Normalized firing rate')
  217. a.set_xlim(0, 5)
  218. a.set_ylim(-1, maxpsth)
  219. a.set_xticks([0, 1, 2, 3, 4, 5])
  220. #a.set_yticks([0, 1])
  221. #a.legend()
  222. ## bar plot % change of firing for top vs bottom quartile pupil arearate, median
  223. ## across population, one value per firing rate quartile. Separate plots for
  224. ## each opto condition. See Reimer2014 fig5e:
  225. opto2height = {False:med_pcoffs, True:med_pcons}
  226. opto2yerr = {False:np.array([med_pcoffs-lci_rspcoffmeds, uci_rspcoffmeds-med_pcoffs]),
  227. True:np.array([med_pcons-lci_rspconmeds, uci_rspconmeds-med_pcons])}
  228. for opto in OPTOS:
  229. f, a = plt.subplots(figsize=(3, 4))
  230. wintitle('top bottom qrt pct FR change bar opto=%s' % opto)
  231. x = np.arange(4)
  232. height = opto2height[opto]
  233. yerr = opto2yerr[opto]
  234. color = opto2clr[opto]
  235. a.bar(x, height, yerr=yerr, color=color, ecolor='gray')
  236. #a.hlines(0, 0, 3)
  237. #a.axhline(y=0, c='k', ls='--', alpha=0.5)
  238. a.set_xlabel('Firing rate quartile')
  239. a.set_ylabel('% Change')
  240. a.spines['left'].set_position(('outward', 4))
  241. a.spines['bottom'].set_position(('outward', 4))
  242. #a.spines['bottom'].set_visible(False)
  243. a.set_xticks([0, 1, 2, 3])
  244. a.set_xticklabels(['0-25%', '25-50%', '50-75%', '75-100%'], rotation=45, ha='center')
  245. ## bar plot % change of firing for top vs bottom quartile pupil arearate, median
  246. ## across population, one value per firing rate quartile. One plot for both opto conditions.
  247. ## See Reimer2014 fig5e:
  248. w = 0.4 # bar width
  249. opto2x = {False:np.arange(-w/2, 4-w/2, 1), True:np.arange(w/2, 4+w/2, 1)}
  250. opto2height = {False:med_pcoffs, True:med_pcons}
  251. opto2yerr = {False:np.array([med_pcoffs-lci_rspcoffmeds, uci_rspcoffmeds-med_pcoffs]),
  252. True:np.array([med_pcons-lci_rspconmeds, uci_rspconmeds-med_pcons])}
  253. opto2label = {False:'V1 Control', True:'V1 Suppressed'}
  254. f, a = plt.subplots(figsize=(3, 3))
  255. wintitle('top bottom qrt pct FR change bar opto=both')
  256. for opto in OPTOS:
  257. x = opto2x[opto]
  258. height = opto2height[opto]
  259. yerr = opto2yerr[opto]
  260. color = opto2clr[opto]
  261. label = opto2label[opto]
  262. a.bar(x, height, width=w, yerr=yerr, color=color, label=label, ecolor='gray')
  263. #a.hlines(0, 0, 3)
  264. #a.axhline(y=0, c='k', ls='--', alpha=0.5)
  265. a.set_xlabel('Firing rate quartile')
  266. a.set_ylabel('% Firing rate change')
  267. a.spines['left'].set_position(('outward', 4))
  268. a.spines['bottom'].set_position(('outward', 4))
  269. #a.spines['bottom'].set_visible(False)
  270. a.set_xticks([0, 1, 2, 3])
  271. a.set_xticklabels(['0-25%', '25-50%', '50-75%', '75-100%'], rotation=45, ha='center')
  272. #ymin = np.floor(min(lci_rspcoffmeds.min(), lci_rspconmeds.min()))
  273. ymin = -1.5
  274. ymax = np.ceil(max(uci_rspcoffmeds.max(), uci_rspconmeds.max()))
  275. a.set_ylim(ymin=ymin, ymax=ymax)
  276. #a.legend()
  277. ## calculate mean FR, reliability, and SNR for top and bottom pupil arearate quartiles:
  278. columns = ['mseu', 'opto', 'tqr', 'bqr', 'tqrel', 'bqrel', 'tqsnr', 'bqsnr']
  279. fig5S2 = []
  280. for mseustr in allmseustrs:
  281. arearate_mviresprow = arearate_mviresp.loc[mseustr]
  282. tq_trialmats = arearate_mviresprow['tq_trialmat']
  283. bq_trialmats = arearate_mviresprow['bq_trialmat']
  284. if np.any(pd.isna(tq_trialmats)) or np.any(pd.isna(bq_trialmats)):
  285. continue
  286. for opto in OPTOS:
  287. tq_trialmat = tq_trialmats[opto]
  288. bq_trialmat = bq_trialmats[opto]
  289. tqr = np.nanmean(tq_trialmat) # top quartile, mean rate
  290. bqr = np.nanmean(bq_trialmat) # bottom quartile, mean rate
  291. tqrel, _ = reliability(tq_trialmat, average='mean', ignore_nan=True)
  292. bqrel, _ = reliability(bq_trialmat, average='mean', ignore_nan=True)
  293. tqsnr = snr_baden2016(tq_trialmat)
  294. bqsnr = snr_baden2016(bq_trialmat)
  295. # skip mseu that have mean rates that fall below thresh due to being limited
  296. # by periods of pupil area dynamics:
  297. if tqr < RATETHRESH and bqr < RATETHRESH:
  298. continue
  299. row = {}
  300. row['mseu'] = mseustr
  301. row['opto'] = opto
  302. row['tqr'] = tqr # top quartile mean firing rate
  303. row['bqr'] = bqr
  304. row['tqrel'] = tqrel # top quartile reliability
  305. row['bqrel'] = bqrel
  306. row['tqsnr'] = tqsnr # top quartile SNR
  307. row['bqsnr'] = bqsnr
  308. fig5S2.append(row)
  309. fig5S2 = pd.DataFrame(fig5S2).set_index(['mseu', 'opto'])
  310. ## scatter plot top vs bottom pupil arearate quartiles for meanrate, reliability, and SNR.
  311. ## See Reimer2014 fig5fghi:
  312. figsize = DEFAULTFIGURESIZE[0]*1.02, DEFAULTFIGURESIZE[1] # tweak to make space for log units
  313. for opto in OPTOS:
  314. rows = fig5S2.loc[(slice(None), opto), :]
  315. normlis, = np.where(rows.reset_index()['mseu'] != exmplmseustr)
  316. exmpli, = np.where(rows.reset_index()['mseu'] == exmplmseustr)
  317. ## scatter plot mean firing rates during top vs. bottom quartile pupil area
  318. ## dilation/constriction rate:
  319. f, a = plt.subplots(figsize=figsize)
  320. wintitle('top bottom qrt scatter meanrate opto=%s' % opto)
  321. # replace any FRs < MINFRVAL with MINFRVAL, and any > MAXFRVAL with MAXFRVAL, for plotting:
  322. #logmin, logmax = -0.5, 1.7
  323. logmin, logmax = -0.9, 1.9
  324. logticks = np.array([0, 1])
  325. MINFRVAL, MAXFRVAL = 10**logmin, 10**logmax
  326. tqr, bqr = rows['tqr'].values, rows['bqr'].values
  327. tqr[tqr < MINFRVAL] = MINFRVAL
  328. bqr[bqr < MINFRVAL] = MINFRVAL
  329. tqr[tqr > MAXFRVAL] = MAXFRVAL
  330. bqr[bqr > MAXFRVAL] = MAXFRVAL
  331. # plot y=x line:
  332. linmin, linmax = MINFRVAL, MAXFRVAL
  333. xyline = [linmin, linmax], [linmin, linmax]
  334. a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1)
  335. # plot normal points:
  336. a.scatter(bqr[normlis], tqr[normlis], clip_on=False, marker='.',
  337. c='None', edgecolor='black', s=DEFSZ)
  338. # plot example point:
  339. a.scatter(bqr[exmpli], tqr[exmpli], clip_on=False, marker='x',
  340. c=green, s=60)
  341. a.set_title('FR (Hz), opto=%s' % opto)
  342. a.set_ylabel("Top 1/4 arearate")
  343. a.set_xlabel("Bottom 1/4 arearate")
  344. a.set_xscale('log')
  345. a.set_yscale('log')
  346. a.set_xlim(MINFRVAL, MAXFRVAL)
  347. a.set_ylim(MINFRVAL, MAXFRVAL)
  348. a.set_xticks(10.0**logticks)
  349. a.set_yticks(a.get_xticks()) # make log scale y ticks the same as x ticks
  350. a.minorticks_off()
  351. axes_disable_scientific(a)
  352. a.set_aspect('equal')
  353. a.spines['left'].set_position(('outward', 4))
  354. a.spines['bottom'].set_position(('outward', 4))
  355. t, p = ttest_rel(bqr, tqr) # paired t-test
  356. a.add_artist(AnchoredText('p$=$%.2g' % p, loc='lower right', frameon=False))
  357. ## scatter plot reliability during top vs. bottom quartile pupil area
  358. ## dilation/constriction rate:
  359. f, a = plt.subplots(figsize=figsize)
  360. wintitle('top bottom qrt scatter rel opto=%s' % opto)
  361. tqrel, bqrel = rows['tqrel'].values, rows['bqrel'].values
  362. # plot y=x line:
  363. linmin, linmax = -0.002, 0.06
  364. xyline = [linmin, linmax], [linmin, linmax]
  365. a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1)
  366. # plot normal points:
  367. a.scatter(bqrel[normlis], tqrel[normlis], clip_on=False, marker='.',
  368. c='None', edgecolor='black', s=DEFSZ)
  369. # plot example point:
  370. a.scatter(bqrel[exmpli], tqrel[exmpli], clip_on=False, marker='x',
  371. c=green, s=60)
  372. a.set_title('Reliability, opto=%s' % opto)
  373. a.set_ylabel("Top 1/4 arearate")
  374. a.set_xlabel("Bottom 1/4 arearate")
  375. #a.set_xscale('log')
  376. #a.set_yscale('log')
  377. a.set_xlim(linmin, linmax)
  378. a.set_ylim(linmin, linmax)
  379. #a.set_xticks(10.0**logticks)
  380. a.set_xticks([0, linmax])
  381. a.set_yticks(a.get_xticks()) # make log scale y ticks the same as x ticks
  382. a.minorticks_off()
  383. axes_disable_scientific(a)
  384. a.set_aspect('equal')
  385. a.spines['left'].set_position(('outward', 4))
  386. a.spines['bottom'].set_position(('outward', 4))
  387. # filter out nans for t-test:
  388. t, p = ttest_rel(bqrel, tqrel) # paired t-test
  389. a.add_artist(AnchoredText('p$=$%.2g' % p, loc='lower right', frameon=False))
  390. ## scatter plot SNR during top vs. bottom quartile pupil area
  391. ## dilation/constriction rate:
  392. f, a = plt.subplots(figsize=figsize)
  393. wintitle('top bottom qrt scatter snr opto=%s' % opto)
  394. tqsnr, bqsnr = rows['tqsnr'].values, rows['bqsnr'].values
  395. # plot y=x line:
  396. linmin, linmax = 0, 0.7
  397. xyline = [linmin, linmax], [linmin, linmax]
  398. a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1)
  399. # plot normal points:
  400. a.scatter(bqsnr[normlis], tqsnr[normlis], clip_on=False, marker='.',
  401. c='None', edgecolor='black', s=DEFSZ)
  402. # plot example point:
  403. a.scatter(bqsnr[exmpli], tqsnr[exmpli], clip_on=False, marker='x',
  404. c=green, s=60)
  405. a.set_title('SNR, opto=%s' % opto)
  406. a.set_ylabel("Top 1/4 arearate")
  407. a.set_xlabel("Bottom 1/4 arearate")
  408. #a.set_xscale('log')
  409. #a.set_yscale('log')
  410. a.set_xlim(linmin, linmax)
  411. a.set_ylim(linmin, linmax)
  412. #a.set_xticks(10.0**logticks)
  413. a.set_xticks([0, linmax])
  414. a.set_yticks(a.get_xticks()) # make log scale y ticks the same as x ticks
  415. a.minorticks_off()
  416. axes_disable_scientific(a)
  417. a.set_aspect('equal')
  418. a.spines['left'].set_position(('outward', 4))
  419. a.spines['bottom'].set_position(('outward', 4))
  420. # filter out nans for t-test:
  421. t, p = ttest_rel(bqsnr, tqsnr) # paired t-test
  422. a.add_artist(AnchoredText('p$=$%.2g' % p, loc='lower right', frameon=False))