fig1.py 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. """Figure 1 and 1S2 plots, and first and last 2 sec scatter plots for 4S1, use run -i fig1.py"""
  2. mi = pd.MultiIndex.from_product([mvimseustrs, OPTOS], names=['mseu', 'opto'])
  3. # include single trial and trial-averaged columns:
  4. columns = ['trialis', 'rates', 'rate02s', 'rate35s', 'burstratios',
  5. 'blankrates', 'blankburstratios'] + modmeasuresnoblankcond
  6. fig1 = pd.DataFrame(index=mi, columns=columns) # excludes kind and st8
  7. # plot movie rasters for each unit by kind, state and opto condition:
  8. showbursts = True
  9. SCATTER = True # True: low quality, but fast; False: high quality, but slow
  10. trialiis = None #np.arange(120) # plot only these trials, None plots all trials
  11. for mseustr in []:#mvimseu2exmpli: #mvimseustrs:
  12. for kind in ['nat']: #MVIKINDS
  13. for st8 in ['none']:
  14. for opto in OPTOS:
  15. dt = mviresp.loc[mseustr, kind, st8, opto]['dt'] # stimulus duration (s)
  16. wdt = -OFFSETS[0] + dt + OFFSETS[1] # wide raster duration, sec
  17. tmin, tmax = 0 + OFFSETS[0], dt + OFFSETS[1]
  18. optotrange = mviresp.loc[mseustr, kind, st8, opto]['optotrange']
  19. raster = mviresp.loc[mseustr, kind, st8, opto]['wraster']
  20. if np.any(pd.isna(raster)): # no raster for this condition
  21. continue
  22. title = '%s movie %s %s %s raster' % (mseustr, kind, st8, opto)
  23. if trialiis is not None:
  24. raster = raster[trialiis]
  25. title += ' %dtrials' % len(trialiis)
  26. burstis = None
  27. if showbursts:
  28. wburstis = mviresp.loc[mseustr, kind, st8, opto]['wburstis']
  29. a = simpletraster(raster=raster, alpha=0.5, s=1, dt=dt, offsets=OFFSETS,
  30. scatter=SCATTER,
  31. title=title, inchespersec=1.5*RASTERSCALEX,
  32. inchespertrial=1/25*RASTERSCALEX,
  33. xaxis=True, burstis=wburstis)
  34. if opto:
  35. # plot horizontal line signifying opto ON period, just above axes:
  36. ton, toff = optotrange
  37. a.hlines(-5, ton, toff, colors=optoblue, lw=4, clip_on=False,
  38. in_layout=False)
  39. # plot horizontal line signifying stimulus period, just above axes:
  40. a.hlines(-2, 0, dt, colors='k', lw=4, clip_on=False, in_layout=False)
  41. # plot vertical coloured line just right of axes:
  42. #vlinexpos = dt + OFFSETS[1] + wdt*0.01
  43. #y0, y1 = a.get_ylim()
  44. #clr = st82clr[st8]
  45. #alpha = opto2alpha[opto]
  46. #a.vlines(vlinexpos, y0, y1, colors=clr, lw=4, alpha=alpha, clip_on=False,
  47. # in_layout=False)
  48. a.set_xlim(tmin, tmax)
  49. # plot movie PSTHs for each unit by kind, overplot state and opto combinations:
  50. for mseustr in []: #mvimseu2exmpli:#['Ntsr1Cre_2020_0001_s04_e10_u12']: #mvimseustrs
  51. for kind in MVIKINDS:
  52. wt = mviresp.loc[mseustr, kind]['wt'] # DataFrame
  53. wpsth = mviresp.loc[mseustr, kind]['wpsth'] # DataFrame
  54. wbpsth = mviresp.loc[mseustr, kind]['wbpsth'] # DataFrame
  55. #t = mviresp.loc[mseustr, kind]['t'] # DataFrame
  56. psth = mviresp.loc[mseustr, kind]['psth'] # DataFrame
  57. if np.isnan(np.hstack(wpsth)).any(): # no PSTH for at least one condition for this mseu
  58. continue
  59. optorho, optorho_p = scipy.stats.pearsonr(psth['none', False], psth['none', True])
  60. runsitrho, runsitrho_p = scipy.stats.pearsonr(psth['run', False], psth['sit', False])
  61. skewoff = scipy.stats.skew(psth['none', False])
  62. skewon = scipy.stats.skew(psth['none', True])
  63. skewrun = scipy.stats.skew(psth['run', False])
  64. skewsit = scipy.stats.skew(psth['sit', False])
  65. _, optoKS_p = ks_2samp(psth['none', False], psth['none', True])
  66. _, runsitKS_p = ks_2samp(psth['run', False], psth['sit', False])
  67. print('%s example PSTH:\n'
  68. 'optorho=%g optorho_p=%g skewoff=%g skewon=%g optoKS_p=%g\n'
  69. 'runsitrho=%g runsitrho_p=%g skewrun=%g skewsit=%g runsitKS_p=%g'
  70. % (mseustr,
  71. optorho, optorho_p, skewoff, skewon, optoKS_p,
  72. runsitrho, runsitrho_p, skewrun, skewsit, runsitKS_p))
  73. for st8combo, optocombo in zip(ST8COMBOS, OPTOCOMBOS):
  74. st8combostr = ' '.join(st8combo)
  75. optocombostr = ' '.join([str(opto) for opto in optocombo])
  76. dt = mviresp.loc[mseustr, kind, 'none']['dt'].mean() # mean stimulus duration (s)
  77. wdt = -OFFSETS[0] + dt + OFFSETS[1] # wide raster duration, sec
  78. tmin, tmax = 0 + OFFSETS[0], dt + OFFSETS[1]
  79. figsize = 0.872 + wdt*1.5*RASTERSCALEX, PSTHHEIGHT
  80. f, a = plt.subplots(figsize=figsize)
  81. title = '%s %s %s %s PSTH' % (mseustr, kind, st8combostr, optocombostr)
  82. wintitle(title)
  83. # subsample as in PSTH scatter plots, and plot all 4 st8/opto combinations:
  84. for st8 in st8combo:
  85. color = st82clr[st8]
  86. for opto in optocombo:
  87. if st8combo == ['run', 'sit'] and optocombo == [True]:
  88. optoalpha = 1
  89. else:
  90. optoalpha = opto2alpha[opto]
  91. if optocombo == [False]: # desaturate bursts by st8, not opto
  92. burstalpha = st82alpha[st8]
  93. else:
  94. burstalpha = opto2alpha[opto]
  95. c = desat(color, optoalpha) # do manual alpha mixing
  96. bc = desat(burstclr, burstalpha) # do manual alpha mixing
  97. fb = opto2fb[opto].title()
  98. if st8 == 'none':
  99. label = fb
  100. else:
  101. label = ', '.join([fb, st8.title()])
  102. a.plot(wt[st8, opto][::ssx], wpsth[st8, opto][::ssx],
  103. '-', color=c, label=label)
  104. a.plot(wt[st8, opto][::ssx], wbpsth[st8, opto][::ssx],
  105. '-', color=bc, label=label+', Burst')
  106. l = a.legend(frameon=False)
  107. l.set_draggable(True)
  108. a.set_xlabel('Time (s)')
  109. a.set_ylabel('Firing rate (spk/s)')
  110. a.set_xlim(tmin, tmax)
  111. # plot horizontal line signifying stimulus period, just below data:
  112. ymin, ymax = a.get_ylim()
  113. a.hlines(-ymax*0.025, 0, dt, colors='k', lw=4, clip_on=False, in_layout=False)
  114. a.set_ylim(ymin, ymax) # restore y limits from before plotting the hline
  115. # plot PDFs, CDFs and QQ of PSTHs for each unit by kind, overplot state and opto combinations:
  116. percentiles = np.arange(0, 100, 2)
  117. figsize = DEFAULTFIGURESIZE
  118. for mseustr in mvimseu2exmpli: #mvimseustrs
  119. if EXPTYPE != 'pvmvis':
  120. break # skip these plots
  121. for kind in MVIKINDS:
  122. psths = mviresp.loc[mseustr, kind]['psth']
  123. if np.isnan(np.hstack(psths)).any(): # no PSTH for at least one condition for this mseu
  124. continue
  125. for st8combo, optocombo in zip(ST8COMBOS, OPTOCOMBOS):
  126. st8combostr = ' '.join(st8combo)
  127. optocombostr = ' '.join([str(opto) for opto in optocombo])
  128. pdff, pdfa = plt.subplots(figsize=figsize) # PDF
  129. title = '%s %s %s %s PSTH PDF' % (mseustr, kind, st8combostr, optocombostr)
  130. wintitle(title)
  131. hpdff, hpdfa = plt.subplots(figsize=(figsize[0], 3)) # horizontal, match PSTH height
  132. title = '%s %s %s %s horizontal PSTH PDF' % (mseustr, kind, st8combostr, optocombostr)
  133. wintitle(title)
  134. npdff, npdfa = plt.subplots(figsize=figsize) # normalized PDF
  135. title = '%s %s %s %s PSTH nPDF' % (mseustr, kind, st8combostr, optocombostr)
  136. wintitle(title)
  137. cdff, cdfa = plt.subplots(figsize=figsize)
  138. title = '%s %s %s %s PSTH CDF' % (mseustr, kind, st8combostr, optocombostr)
  139. wintitle(title)
  140. qqf, qqa = plt.subplots(figsize=figsize)
  141. title = '%s %s %s %s PSTH QQ' % (mseustr, kind, st8combostr, optocombostr)
  142. wintitle(title)
  143. # plot PDFs, CDFs and QQ of all st8/opto combinations:
  144. for st8 in st8combo:
  145. c = st82clr[st8]
  146. qq = {}
  147. for opto in optocombo:
  148. psth = psths[st8, opto][::ssx]
  149. npsth = psth / psth.max() # normalize
  150. uvals = np.unique(npsth)
  151. qq[opto] = np.percentile(psth, percentiles)
  152. fb = opto2fb[opto].title()
  153. if st8 == 'none':
  154. label = fb
  155. else:
  156. label = ', '.join([fb, st8.title()])
  157. alpha = opto2alpha[opto]
  158. nbins = intround(np.sqrt(len(psth)))
  159. pdfa.hist(psth, bins=nbins, density=True, histtype='step',
  160. color=c, alpha=alpha, label=label)
  161. hpdfa.hist(psth, bins=nbins, density=True, histtype='step',
  162. color=c, alpha=alpha, label=label, orientation='horizontal')
  163. npdfa.hist(npsth, bins=nbins, density=True, histtype='step',
  164. color=c, alpha=alpha, label=label)
  165. cdfa.hist(npsth, bins=uvals, density=True, cumulative=True, histtype='step',
  166. color=c, alpha=alpha, label=label)
  167. if len(optocombo) == 2:
  168. qqa.scatter(qq[False], qq[True], marker='.', c=c)
  169. #l = a.legend(frameon=False)
  170. #l.set_draggable(True)
  171. pdfa.set_xlabel('Firing rate (spk/s)')
  172. pdfa.set_ylabel('Probability density')
  173. #pdfa.set_yticks([0, 0.5, 1])
  174. pdff.show()
  175. hpdfa.set_xlabel('Probability density')
  176. hpdfa.set_ylabel('Firing rate (spk/s)')
  177. hpdff.show()
  178. npdfa.set_xlabel('Normalized rate')
  179. npdfa.set_ylabel('Probability density')
  180. #pdfa.set_yticks([0, 0.5, 1])
  181. npdff.show()
  182. cdfa.set_xlabel('Normalized rate')
  183. cdfa.set_ylabel('Cumulative probability')
  184. cdfa.set_yticks([0, 0.5, 1])
  185. cdff.show()
  186. if len(optocombo) == 2:
  187. qqmax = np.ceil(np.array(qqa.dataLim).max())
  188. qqxyline = [0, qqmax], [0, qqmax]
  189. qqa.plot(qqxyline[0], qqxyline[1], '--', color='gray', zorder=-1)
  190. qqa.set_xlabel('Feedback rate (spk/s)')
  191. qqa.set_ylabel('Suppression rate (spk/s)')
  192. qqa.set_xlim([0, qqmax])
  193. qqa.set_ylim([0, qqmax])
  194. qqa.set_aspect('equal')
  195. #qqa.set_xticks([0, 0.5, 1])
  196. #qqa.set_yticks([0, 0.5, 1])
  197. qqf.show()
  198. # plot one PSTH PDF, CDF and QQ, for each combination of kind, state and opto,
  199. # each pooled across all mseu:
  200. percentiles = np.arange(0, 100, 2)
  201. figsize = DEFAULTFIGURESIZE
  202. for kind in MVIKINDS:
  203. if EXPTYPE != 'pvmvis':
  204. break # skip these plots
  205. for st8combo in ST8COMBOS:
  206. pdff, pdfa = plt.subplots(figsize=figsize)
  207. title = 'mean %s %s PSTH PDF' % (kind, ' '.join(st8combo))
  208. wintitle(title)
  209. cdff, cdfa = plt.subplots(figsize=figsize)
  210. title = 'mean %s %s PSTH CDF' % (kind, ' '.join(st8combo))
  211. wintitle(title)
  212. qqf, qqa = plt.subplots(figsize=figsize)
  213. title = 'mean %s %s PSTH QQ' % (kind, ' '.join(st8combo))
  214. wintitle(title)
  215. for st8 in st8combo:
  216. c = st82clr[st8]
  217. qq = {}
  218. for opto in OPTOS:
  219. psths, npsths = [], []
  220. for mseustr in mvimseustrs: #mvimseu2exmpli
  221. psth = mviresp.loc[mseustr, kind, st8, opto]['psth']
  222. if np.isnan(psth).any(): # no PSTH for this mseu
  223. continue
  224. #psth = psth[::ssx] # no need to subsample, only calculating a few CDFs
  225. psths.append(psth)
  226. npsths.append(psth / psth.max()) # normalize
  227. psths, npsths = np.concatenate(psths), np.concatenate(npsths)
  228. uvals = np.unique(npsths)
  229. qq[opto] = np.percentile(psths, percentiles)
  230. fb = opto2fb[opto].title()
  231. if st8 == 'none':
  232. label = fb
  233. else:
  234. label = ', '.join([fb, st8.title()])
  235. alpha = opto2alpha[opto]
  236. pdfa.hist(npsths, bins=50, density=True, histtype='step',
  237. color=c, alpha=alpha, label=label)
  238. cdfa.hist(npsths, uvals, density=True, cumulative=True, histtype='step',
  239. color=c, alpha=alpha, label=label)
  240. qqa.scatter(qq[False], qq[True], marker='.', c=c)
  241. #l = a.legend(frameon=False)
  242. #l.set_draggable(True)
  243. pdfa.set_xlabel('Normalized rate')
  244. pdfa.set_ylabel('Probability density')
  245. #pdfa.set_yticks([0, 0.5, 1])
  246. pdff.show()
  247. cdfa.set_xlabel('Normalized rate')
  248. cdfa.set_ylabel('Cumulative probability')
  249. cdfa.set_yticks([0, 0.5, 1])
  250. cdff.show()
  251. qqmax = np.ceil(np.array(qqa.dataLim).max())
  252. qqxyline = [0, qqmax], [0, qqmax]
  253. qqa.plot(qqxyline[0], qqxyline[1], '--', color='gray', zorder=-1)
  254. qqa.set_xlabel('Feedback rate (spk/s)')
  255. qqa.set_ylabel('Suppression rate (spk/s)')
  256. #qqa.set_aspect('equal', 'datalim')
  257. qqa.set_xlim([0, qqmax])
  258. qqa.set_ylim([0, qqmax])
  259. #qqa.set_xticks([0, 0.5, 1])
  260. #print('%s xticks: %r' % (title, qqa.get_xticks()))
  261. #qqa.set_yticks(qqa.get_xticks())
  262. qqf.show()
  263. # scatter plot movie meanrates:
  264. figsize = DEFAULTFIGURESIZE[0]*1.02, DEFAULTFIGURESIZE[1] # tweak to make space for log units
  265. logmin, logmax = -1, 2
  266. logticks = np.array([-1, 0, 1, 2])
  267. #log0min = logmin + 0.05
  268. for kind in ['nat']:#MVIKINDS:
  269. for st8 in ['none']:#ALLST8S:
  270. f, a = plt.subplots(figsize=figsize)
  271. wintitle('opto meanrate movie %s %s' % (kind, st8))
  272. rons, roffs, sgnfs, exmplis, exmplmseustrs, normlis = [], [], [], [], [], []
  273. keptmseui = 0 # manually init and increment instead of using enumerate()
  274. for mseustr in mvimseustrs:
  275. meanrate = mviresp.loc[mseustr, kind, st8]['meanrate']
  276. snr = mviresp.loc[mseustr, kind, st8]['snr']
  277. if meanrate.isna().any(): # missing one or both meanrates
  278. continue
  279. if (snr < SNRTHRESH).all(): # neither condition has decent SNR
  280. continue
  281. rons.append(meanrate[True])
  282. roffs.append(meanrate[False])
  283. trialis = mviresp.loc[mseustr, kind, st8]['trialis']
  284. rates = mviresp.loc[mseustr, kind, st8]['rates']
  285. _, pval = ttest_ind(rates[False], rates[True], equal_var=False)
  286. sgnfs.append(pval < SCATTERPTHRESH) # bool
  287. fig1.loc[mseustr, 'meanrate'] = meanrate[False], meanrate[True] # save
  288. fig1.loc[mseustr]['trialis'] = trialis # save, for joining DataFrames trial-wise
  289. fig1.loc[mseustr]['rates'] = rates # save trial-wise values
  290. if mvimseu2exmpli.get(mseustr) == fig1exmpli:
  291. exmplis.append(keptmseui)
  292. exmplmseustrs.append(mseustr)
  293. else:
  294. normlis.append(keptmseui)
  295. keptmseui += 1 # manually increment
  296. rons = np.asarray(rons)
  297. roffs = np.asarray(roffs)
  298. sgnfs = np.asarray(sgnfs)
  299. # plot y=x line:
  300. xyline = [10**logmin, 10**logmax], [10**logmin, 10**logmax]
  301. a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1)
  302. insgnfis, = np.where(sgnfs == False)
  303. sgnfis, = np.where(sgnfs == True)
  304. normlinsgnfis = np.intersect1d(normlis, insgnfis)
  305. normlsgnfis = np.intersect1d(normlis, sgnfis)
  306. if len(normlinsgnfis) > 0:
  307. # plot normal (non-example) insignificant points:
  308. c = desat(st82clr[st8], SGNF2ALPHA[False]) # do manual alpha mixing
  309. a.scatter(rons[normlinsgnfis], roffs[normlinsgnfis], clip_on=False,
  310. marker='.', c='None', edgecolor=c, s=DEFSZ)
  311. if len(normlsgnfis) > 0:
  312. # plot normal (non-example) significant points:
  313. c = desat(st82clr[st8], SGNF2ALPHA[True]) # do manual alpha mixing
  314. a.scatter(rons[normlsgnfis], roffs[normlsgnfis], clip_on=False,
  315. marker='.', c='None', edgecolor=c, s=DEFSZ)
  316. # plot example points, one at a time:
  317. for exmpli, mseustr in zip(exmplis, exmplmseustrs):
  318. marker = exmpli2mrk[mvimseu2exmpli[mseustr]]
  319. c = exmpli2clr[mvimseu2exmpli[mseustr]]
  320. sz = exmpli2sz[mvimseu2exmpli[mseustr]]
  321. lw = exmpli2lw[mvimseu2exmpli[mseustr]]
  322. a.scatter(rons[exmpli], roffs[exmpli], clip_on=False,
  323. marker=marker, c=c, s=sz, lw=lw)
  324. a.set_xlabel('Suppression FR (spk/s)')
  325. a.set_ylabel('Feedback FR (spk/s)')
  326. a.set_xscale('log')
  327. a.set_yscale('log')
  328. a.set_xlim(10**logmin, 10**logmax)
  329. a.set_ylim(10**logmin, 10**logmax)
  330. a.set_xticks(10.0**logticks)
  331. a.set_yticks(a.get_xticks()) # make log scale y ticks the same as x ticks
  332. a.minorticks_off()
  333. axes_disable_scientific(a)
  334. a.set_aspect('equal')
  335. a.spines['left'].set_position(('outward', 4))
  336. a.spines['bottom'].set_position(('outward', 4))
  337. #t, p = ttest_rel(rons, roffs) # paired t-test
  338. #a.add_artist(AnchoredText('p$=$%.2g' % p, loc='lower right', frameon=False))
  339. #mu = rons.mean(), roffs.mean()
  340. #txt = '$\mathregular{\mu=%.1f, %.1f}$' % mu
  341. #a.add_artist(AnchoredText(txt, loc='upper left', frameon=False))
  342. # plot mean firing rate PDF:
  343. f, a = plt.subplots(figsize=figsize)
  344. wintitle('opto meanrate PDF movie %s %s' % (kind, st8))
  345. bins = np.logspace(-1, 2, num=25, base=10) # end inclusive
  346. a.hist(roffs, bins=bins, histtype='step', density=False, color='k',
  347. label='Feedback', clip_on=False)
  348. a.hist(rons, bins=bins, histtype='step', density=False, color=optoblue,
  349. label='V1 Suppression', clip_on=False)
  350. a.set_xlabel('Mean firing rate (spk/s)')
  351. a.set_ylabel('Cell count')
  352. a.set_xscale('log')
  353. a.set_xlim(10**logmin, 10**logmax)
  354. a.set_xticks(10.0**logticks)
  355. a.minorticks_off()
  356. axes_disable_scientific(a)
  357. #l = a.legend(frameon=False)
  358. #l.set_draggable(True)
  359. # scatter plot movie burst ratio:
  360. figsize = DEFAULTFIGURESIZE[0]*1.04, DEFAULTFIGURESIZE[1] # tweak to make space for log units
  361. logmin, logmax = -3.55, 0
  362. if EXPTYPE == 'ntsrmvis':
  363. logmin, logmax = -3.83, 0
  364. logticks = np.array([-3, -2, -1, 0])
  365. for kind in ['nat']:#MVIKINDS:
  366. for st8 in ['none']:#ALLST8S:
  367. f, a = plt.subplots(figsize=figsize)
  368. wintitle('opto burst ratio movie %s %s' % (kind, st8))
  369. brons, broffs, sgnfs, exmplis, exmplmseustrs, normlis = [], [], [], [], [], []
  370. keptmseui = 0 # manually init and increment instead of using enumerate()
  371. for mseustr in mvimseustrs:
  372. br = mviresp.loc[mseustr, kind, st8]['meanburstratio']
  373. snr = mviresp.loc[mseustr, kind, st8]['snr']
  374. if br.isna().any(): # missing for at least one opto condition
  375. continue
  376. if (snr < SNRTHRESH).all(): # neither condition has decent SNR
  377. continue
  378. brons.append(br[True])
  379. broffs.append(br[False])
  380. burstratios = mviresp.loc[mseustr, kind, st8]['burstratios']
  381. _, pval = ttest_ind(burstratios[False], burstratios[True], equal_var=False)
  382. sgnfs.append(pval < SCATTERPTHRESH) # bool
  383. fig1.loc[mseustr, 'meanburstratio'] = br[False], br[True] # save
  384. fig1.loc[mseustr]['burstratios'] = burstratios # save trial-wise values
  385. if mvimseu2exmpli.get(mseustr) == fig1exmpli:
  386. exmplis.append(keptmseui)
  387. exmplmseustrs.append(mseustr)
  388. else:
  389. normlis.append(keptmseui)
  390. keptmseui += 1 # manually increment
  391. brons, broffs = np.asarray(brons), np.asarray(broffs)
  392. sgnfs = np.asarray(sgnfs)
  393. # plot y=x line:
  394. xyline = [10**logmin, 10**logmax], [10**logmin, 10**logmax]
  395. a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1)
  396. insgnfis, = np.where(sgnfs == False)
  397. sgnfis, = np.where(sgnfs == True)
  398. normlinsgnfis = np.intersect1d(normlis, insgnfis)
  399. normlsgnfis = np.intersect1d(normlis, sgnfis)
  400. if len(normlinsgnfis) > 0:
  401. # plot normal (non-example) insignificant points:
  402. c = desat(st82clr[st8], SGNF2ALPHA[False]) # do manual alpha mixing
  403. a.scatter(brons[normlinsgnfis], broffs[normlinsgnfis], clip_on=True,
  404. marker='.', c='None', edgecolor=c, s=DEFSZ) # clip_on=False fails
  405. if len(normlsgnfis) > 0:
  406. # plot normal (non-example) significant points:
  407. c = desat(st82clr[st8], SGNF2ALPHA[True]) # do manual alpha mixing
  408. a.scatter(brons[normlsgnfis], broffs[normlsgnfis], clip_on=True,
  409. marker='.', c='None', edgecolor=c, s=DEFSZ) # clip_on=False fails
  410. # plot example points, one at a time:
  411. for exmpli, mseustr in zip(exmplis, exmplmseustrs):
  412. marker = exmpli2mrk[mvimseu2exmpli[mseustr]]
  413. c = exmpli2clr[mvimseu2exmpli[mseustr]]
  414. sz = exmpli2sz[mvimseu2exmpli[mseustr]]
  415. lw = exmpli2lw[mvimseu2exmpli[mseustr]]
  416. a.scatter(brons[exmpli], broffs[exmpli], clip_on=False,
  417. marker=marker, c=c, s=sz, lw=lw)
  418. a.set_xlabel('Suppression BR') # keep it short to maximize space for axes
  419. a.set_ylabel('Feedback BR')
  420. a.set_xscale('log')
  421. a.set_yscale('log')
  422. a.set_xlim(10**logmin, 10**logmax)
  423. a.set_ylim(10**logmin, 10**logmax)
  424. a.set_xticks(10.0**logticks)
  425. a.set_yticks(a.get_xticks()) # make log scale y ticks the same as x ticks
  426. a.minorticks_off()
  427. axes_disable_scientific(a)
  428. a.set_aspect('equal')
  429. a.spines['left'].set_position(('outward', 4))
  430. a.spines['bottom'].set_position(('outward', 4))
  431. #t, p = ttest_rel(brons, broffs) # paired t-test
  432. #a.add_artist(AnchoredText('p$=$%.2g' % p, loc='upper left', frameon=False))
  433. # scatter plot movie PSTH sparseness:
  434. figsize = DEFAULTFIGURESIZE
  435. linmin, linmax, linstep = 0, 1, 0.5
  436. ticks = np.arange(intround(linmin), intround(linmax)+linstep, linstep)
  437. for kind in ['nat']:#MVIKINDS:
  438. for st8 in ['none']:#ALLST8S:
  439. f, a = plt.subplots(figsize=figsize)
  440. wintitle('opto sparseness %s %s' % (kind, st8))
  441. sparsons, sparsoffs, exmplis, exmplmseustrs, normlis = [], [], [], [], []
  442. keptmseui = 0 # manually init and increment instead of using enumerate()
  443. for mseustr in mvimseustrs:
  444. spars = mviresp.loc[mseustr, kind, st8]['spars']
  445. snr = mviresp.loc[mseustr, kind, st8]['snr']
  446. if spars.isna().any(): # missing for at least one opto condition
  447. continue
  448. if (snr < SNRTHRESH).all(): # neither condition has decent SNR
  449. continue
  450. sparsons.append(spars[True])
  451. sparsoffs.append(spars[False])
  452. fig1.loc[mseustr, 'spars'] = spars[False], spars[True] # save
  453. if mvimseu2exmpli.get(mseustr) == fig1exmpli:
  454. exmplis.append(keptmseui)
  455. exmplmseustrs.append(mseustr)
  456. else:
  457. normlis.append(keptmseui)
  458. keptmseui += 1 # manually increment
  459. sparsons, sparsoffs = np.asarray(sparsons), np.asarray(sparsoffs)
  460. # plot y=x line:
  461. xyline = [linmin, linmax], [linmin, linmax]
  462. a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1)
  463. # plot normal (non-example) points:
  464. a.scatter(sparsons[normlis], sparsoffs[normlis], clip_on=False,
  465. marker='.', c='None', edgecolor=st82clr[st8], s=DEFSZ)
  466. # plot example points, one at a time:
  467. for exmpli, mseustr in zip(exmplis, exmplmseustrs):
  468. marker = exmpli2mrk[mvimseu2exmpli[mseustr]]
  469. c = exmpli2clr[mvimseu2exmpli[mseustr]]
  470. sz = exmpli2sz[mvimseu2exmpli[mseustr]]
  471. lw = exmpli2lw[mvimseu2exmpli[mseustr]]
  472. a.scatter(sparsons[exmpli], sparsoffs[exmpli], clip_on=False,
  473. marker=marker, c=c, s=sz, lw=lw)
  474. a.set_xlabel('Suppression spars') # keep it short to maximize space for axes
  475. a.set_ylabel('Feedback spars')
  476. a.set_xlim(linmin, linmax)
  477. a.set_ylim(linmin, linmax)
  478. a.set_xticks(ticks)
  479. a.set_yticks(ticks)
  480. a.set_aspect('equal')
  481. a.spines['left'].set_position(('outward', 4))
  482. a.spines['bottom'].set_position(('outward', 4))
  483. #t, p = ttest_rel(sparsons, sparsoffs) # paired t-test
  484. #a.add_artist(AnchoredText('p$=$%.2g' % p, loc='upper left', frameon=False))
  485. # scatter plot movie PSTH reliability:
  486. figsize = DEFAULTFIGURESIZE[0]*0.98, DEFAULTFIGURESIZE[1] # tweak to match others
  487. linmin, linmax = 0, 0.52
  488. ticks = 0, 0.5
  489. for kind in ['nat']:#MVIKINDS:
  490. for st8 in ['none']:#ALLST8S:
  491. f, a = plt.subplots(figsize=figsize)
  492. wintitle('opto reliability %s %s' % (kind, st8))
  493. relons, reloffs, sgnfs, exmplis, exmplmseustrs, normlis = [], [], [], [], [], []
  494. keptmseui = 0 # manually init and increment instead of using enumerate()
  495. for mseustr in mvimseustrs:
  496. rel = mviresp.loc[mseustr, kind, st8]['rel']
  497. snr = mviresp.loc[mseustr, kind, st8]['snr']
  498. if rel.isna().any(): # missing for at least one opto condition
  499. continue
  500. if (snr < SNRTHRESH).all(): # neither condition has decent SNR
  501. continue
  502. relons.append(rel[True])
  503. reloffs.append(rel[False])
  504. # collect rhos from all trial pairs, reduce to single rho per trial, use
  505. # to estimate significance of individual units:
  506. rhos = mviresp.loc[mseustr, kind, st8]['rhos']
  507. fullrhos, meanrhos = {}, {}
  508. for opto in OPTOS:
  509. npairs = len(rhos[opto])
  510. # from quadratic formula solution to npairs = ntrials*(ntrials-1) / 2
  511. ntrials = (1 + np.sqrt(1 + 8*npairs)) / 2
  512. assert np.isclose(ntrials, int(ntrials)) # make sure this float is int
  513. ntrials = int(ntrials)
  514. uti = np.triu_indices(ntrials, k=1) # upper indices, excludes diagonal
  515. lti = np.tril_indices(ntrials, k=-1) # lower indices, excludes diagonal
  516. # empty full corr matrix, nans will remain on diagonal and will be ignored:
  517. fullrhos[opto] = np.tile(np.nan, (ntrials, ntrials))
  518. fullrhos[opto][uti] = rhos[opto] # fill the upper triangle
  519. # copy upper to lower triangle,
  520. # see https://stackoverflow.com/a/42209263/2020363:
  521. fullrhos[opto][lti] = fullrhos[opto].T[lti]
  522. meanrhos[opto] = np.nanmean(fullrhos[opto], axis=1) # along either axis is fine
  523. _, pval = ttest_ind(meanrhos[False], meanrhos[True], equal_var=False)
  524. sgnfs.append(pval < SCATTERPTHRESH) # bool
  525. fig1.loc[mseustr, 'rel'] = rel[False], rel[True] # save
  526. if mvimseu2exmpli.get(mseustr) == fig1exmpli:
  527. exmplis.append(keptmseui)
  528. exmplmseustrs.append(mseustr)
  529. else:
  530. normlis.append(keptmseui)
  531. keptmseui += 1 # manually increment
  532. relons, reloffs = np.asarray(relons), np.asarray(reloffs)
  533. sgnfs = np.asarray(sgnfs)
  534. # plot y=x line:
  535. xyline = [linmin, linmax], [linmin, linmax]
  536. a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1)
  537. insgnfis, = np.where(sgnfs == False)
  538. sgnfis, = np.where(sgnfs == True)
  539. normlinsgnfis = np.intersect1d(normlis, insgnfis)
  540. normlsgnfis = np.intersect1d(normlis, sgnfis)
  541. if len(normlinsgnfis) > 0:
  542. # plot normal (non-example) insignificant points:
  543. c = desat(st82clr[st8], SGNF2ALPHA[False]) # do manual alpha mixing
  544. a.scatter(relons[normlinsgnfis], reloffs[normlinsgnfis], clip_on=False,
  545. marker='.', c='None', edgecolor=c, s=DEFSZ)
  546. if len(normlsgnfis) > 0:
  547. # plot normal (non-example) significant points:
  548. c = desat(st82clr[st8], SGNF2ALPHA[True]) # do manual alpha mixing
  549. a.scatter(relons[normlsgnfis], reloffs[normlsgnfis], clip_on=False,
  550. marker='.', c='None', edgecolor=c, s=DEFSZ)
  551. # plot example points, one at a time:
  552. for exmpli, mseustr in zip(exmplis, exmplmseustrs):
  553. marker = exmpli2mrk[mvimseu2exmpli[mseustr]]
  554. c = exmpli2clr[mvimseu2exmpli[mseustr]]
  555. sz = exmpli2sz[mvimseu2exmpli[mseustr]]
  556. lw = exmpli2lw[mvimseu2exmpli[mseustr]]
  557. a.scatter(relons[exmpli], reloffs[exmpli], clip_on=False,
  558. marker=marker, c=c, s=sz, lw=lw)
  559. a.set_xlabel('Suppression rel') # keep it short to maximize space for axes
  560. a.set_ylabel('Feedback rel')
  561. a.set_xlim(linmin, linmax)
  562. a.set_ylim(linmin, linmax)
  563. a.set_xticks(ticks)
  564. a.set_yticks(ticks)
  565. a.set_aspect('equal')
  566. a.spines['left'].set_position(('outward', 4))
  567. a.spines['bottom'].set_position(('outward', 4))
  568. #t, p = ttest_rel(relons, reloffs, nan_policy='omit') # paired t-test
  569. #a.add_artist(AnchoredText('p$=$%.2g' % p, loc='upper left', frameon=False))
  570. # plot movie SNR PDFs, show SNRTHRESH:
  571. figsize = DEFAULTFIGURESIZE
  572. bins = np.arange(0, 0.5, 0.005)
  573. #bins = np.logspace(-2, -0.2, 50, base=10)
  574. for kind in ['nat']:#MVIKINDS:
  575. for st8 in ['none']:#ALLST8S:
  576. for opto in [None, False, True]:
  577. if opto is not None:
  578. snrs = mviresp['snr'][(slice(None), kind, st8, opto)].dropna() # one val per mseu
  579. else:
  580. snrs = mviresp['snr'][(slice(None), kind, st8)].dropna() # two vals per mseu?
  581. snrs = np.float64(snrs) # convert from object array
  582. f, a = plt.subplots(figsize=figsize)
  583. titlestr = 'SNR PDF %s %s' % (kind, st8)
  584. if opto is not None:
  585. titlestr += ' %s' % opto2fb[opto]
  586. wintitle(titlestr, f)
  587. c = st82clr[st8]
  588. a.hist(snrs, bins=bins, density=True, color=c,
  589. alpha=opto2alpha[opto], label=opto2fb[opto])
  590. a.axvline(x=SNRTHRESH, ls='-', marker='', c='gray')#, zorder=-np.inf)
  591. txt = 'n=%d' % len(snrs)
  592. a.add_artist(AnchoredText(txt, loc='upper right', frameon=False,
  593. prop=dict(color=c, alpha=opto2alpha[opto])))
  594. #a.set_xscale('log')
  595. #l = a.legend(frameon=False)
  596. #l.set_draggable(True)
  597. a.set_xlabel('SNR')
  598. if opto is not None:
  599. a.set_xlabel('%s SNR' % opto2fb[opto].title())
  600. a.set_ylabel('Probability density')
  601. # scatter plot movie SNR:
  602. figsize = DEFAULTFIGURESIZE
  603. linmin, linmax = 0, 0.6
  604. ticks = 0, 0.5
  605. for kind in ['nat']:#MVIKINDS:
  606. for st8 in ['none']:#ALLST8S:
  607. f, a = plt.subplots(figsize=figsize)
  608. wintitle('opto SNR %s %s' % (kind, st8))
  609. snrons, snroffs, exmplis, exmplmseustrs, normlis = [], [], [], [], []
  610. keptmseui = 0 # manually init and increment instead of using enumerate()
  611. for mseustr in mvimseustrs:
  612. snr = mviresp.loc[mseustr, kind, st8]['snr']
  613. if snr.isna().any(): # missing for at least one opto condition
  614. continue
  615. if (snr < SNRTHRESH).all(): # neither condition has decent SNR
  616. continue
  617. snrons.append(snr[True])
  618. snroffs.append(snr[False])
  619. fig1.loc[mseustr, 'snr'] = snr[False], snr[True] # save
  620. if mvimseu2exmpli.get(mseustr) == fig1exmpli:
  621. exmplis.append(keptmseui)
  622. exmplmseustrs.append(mseustr)
  623. else:
  624. normlis.append(keptmseui)
  625. keptmseui += 1 # manually increment
  626. snrons, snroffs = np.asarray(snrons), np.asarray(snroffs)
  627. # plot y=x line:
  628. xyline = [linmin, linmax], [linmin, linmax]
  629. a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1)
  630. # plot normal (non-example) points:
  631. a.scatter(snrons[normlis], snroffs[normlis], clip_on=False,
  632. marker='.', c='None', edgecolor=st82clr[st8], s=DEFSZ)
  633. # plot example points, one at a time:
  634. for exmpli, mseustr in zip(exmplis, exmplmseustrs):
  635. marker = exmpli2mrk[mvimseu2exmpli[mseustr]]
  636. c = exmpli2clr[mvimseu2exmpli[mseustr]]
  637. sz = exmpli2sz[mvimseu2exmpli[mseustr]]
  638. lw = exmpli2lw[mvimseu2exmpli[mseustr]]
  639. a.scatter(snrons[exmpli], snroffs[exmpli], clip_on=False,
  640. marker=marker, c=c, s=sz, lw=lw)
  641. a.set_xlabel('Suppression SNR')
  642. a.set_ylabel('Feedback SNR')
  643. a.set_xlim(linmin, linmax)
  644. a.set_ylim(linmin, linmax)
  645. a.set_xticks(ticks)
  646. a.set_yticks(ticks)
  647. a.set_aspect('equal')
  648. a.spines['left'].set_position(('outward', 4))
  649. a.spines['bottom'].set_position(('outward', 4))
  650. #t, p = ttest_rel(snrons, snroffs, nan_policy='omit') # paired t-test
  651. #a.add_artist(AnchoredText('p$=$%.2g' % p, loc='upper left', frameon=False))
  652. # plot movie PSTH peak width distributions:
  653. normalizepeakwidths = True
  654. figsize = DEFAULTFIGURESIZE
  655. for kind in ['nat']:#MVIKINDS:
  656. for st8 in ['none']:#ALLST8S:
  657. f, a = plt.subplots(figsize=figsize)
  658. titlestr = ('opto peak width PDF %s %s PSTHBASELINEMEDIANX=%d PSTHPEAKMINTHRESH=%d'
  659. % (kind, st8, PSTHBASELINEMEDIANX, PSTHPEAKMINTHRESH))
  660. if normalizepeakwidths:
  661. titlestr += " normed"
  662. wintitle(titlestr, f)
  663. pkwons, pkwoffs = [], []
  664. for mseustr in mvimseustrs:
  665. pkws = mviresp.loc[mseustr, kind, st8]['pkws']
  666. snr = mviresp.loc[mseustr, kind, st8]['snr']
  667. if pkws.isna().any():
  668. continue # skip this mseu
  669. if (snr < SNRTHRESH).all(): # neither condition has decent SNR
  670. continue
  671. if normalizepeakwidths:
  672. maxpkw = np.concatenate(pkws.values).max() # max peak width for this mseu
  673. pkws = pkws / maxpkw # normalize all peak widths by maxpkw
  674. pkwons.append(pkws[True])
  675. pkwoffs.append(pkws[False])
  676. c = st82clr[st8]
  677. pkwons, pkwoffs = np.concatenate(pkwons), np.concatenate(pkwoffs)
  678. for opto, pkws, loc in zip(OPTOS, [pkwoffs, pkwons], ['upper right', 'upper left']):
  679. a.hist(pkws, bins=50, density=True, histtype='step', color=c,
  680. alpha=opto2alpha[opto], label=opto2fb[opto])
  681. txt = 'n=%d' % len(pkws)
  682. a.add_artist(AnchoredText(txt, loc=loc, frameon=False,
  683. prop=dict(color=c, alpha=opto2alpha[opto])))
  684. a.set_xscale('log')
  685. #a.set_yscale('log')
  686. axes_disable_scientific(a)
  687. #l = a.legend(frameon=False)
  688. #l.set_draggable(True)
  689. a.set_xlabel('PSTH peak width (s)')
  690. a.set_ylabel('Probability density')
  691. #t, p = ttest_rel(pkwoffs, pkwons, nan_policy='omit') # paired t-test
  692. #a.add_artist(AnchoredText('p$=$%.2g' % p, loc='upper left', frameon=False))
  693. # scatter plot movie PSTH mean peak widths:
  694. figsize = DEFAULTFIGURESIZE[0]*1.05, DEFAULTFIGURESIZE[1] # tweak to make space for log units
  695. linmin, linmax = 0.025, 0.2
  696. ticks = 0.05, 0.1, 0.2
  697. for kind in ['nat']:#MVIKINDS:
  698. for st8 in ['none']:#ALLST8S:
  699. f, a = plt.subplots(figsize=figsize)
  700. wintitle('opto mean peak width %s %s' % (kind, st8))
  701. meanpkwons, meanpkwoffs, exmplis, exmplmseustrs, normlis = [], [], [], [], []
  702. keptmseui = 0 # manually init and increment instead of using enumerate()
  703. for mseustr in mvimseustrs:
  704. meanpkw = mviresp.loc[mseustr, kind, st8]['meanpkw']
  705. snr = mviresp.loc[mseustr, kind, st8]['snr']
  706. if meanpkw.isna().any(): # missing for at least one opto condition
  707. continue
  708. if (snr < SNRTHRESH).all(): # neither condition has decent SNR
  709. continue
  710. meanpkwons.append(meanpkw[True])
  711. meanpkwoffs.append(meanpkw[False])
  712. fig1.loc[mseustr, 'meanpkw'] = meanpkw[False], meanpkw[True] # save
  713. if mvimseu2exmpli.get(mseustr) == fig1exmpli:
  714. exmplis.append(keptmseui)
  715. exmplmseustrs.append(mseustr)
  716. else:
  717. normlis.append(keptmseui)
  718. keptmseui += 1 # manually increment
  719. meanpkwons, meanpkwoffs = np.asarray(meanpkwons), np.asarray(meanpkwoffs)
  720. # plot y=x line:
  721. xyline = [linmin, linmax], [linmin, linmax]
  722. a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1)
  723. # plot normal (non-example) points:
  724. a.scatter(meanpkwons[normlis], meanpkwoffs[normlis], clip_on=False,
  725. marker='.', c='None', edgecolor=st82clr[st8], s=DEFSZ)
  726. # plot example points, one at a time:
  727. for exmpli, mseustr in zip(exmplis, exmplmseustrs):
  728. marker = exmpli2mrk[mvimseu2exmpli[mseustr]]
  729. c = exmpli2clr[mvimseu2exmpli[mseustr]]
  730. sz = exmpli2sz[mvimseu2exmpli[mseustr]]
  731. lw = exmpli2lw[mvimseu2exmpli[mseustr]]
  732. a.scatter(meanpkwons[exmpli], meanpkwoffs[exmpli], clip_on=False,
  733. marker=marker, c=c, s=sz, lw=lw)
  734. a.set_xscale('log', basex=2)
  735. a.set_yscale('log', basey=2)
  736. a.set_xlabel('Suppression pkw (s)') # keep it short to maximize space for axes
  737. a.set_ylabel('Feedback pkw (s)')
  738. a.set_xlim(linmin, linmax)
  739. a.set_ylim(linmin, linmax)
  740. a.set_xticks(ticks)
  741. a.set_yticks(a.get_xticks()) # make log scale y ticks the same as x ticks
  742. a.minorticks_off()
  743. axes_disable_scientific(a)
  744. a.set_aspect('equal')
  745. a.spines['left'].set_position(('outward', 4))
  746. a.spines['bottom'].set_position(('outward', 4))
  747. a.xaxis.set_major_formatter(ScalarFormatter())
  748. a.yaxis.set_major_formatter(ScalarFormatter())
  749. a.xaxis.set_major_formatter(FormatStrFormatter("%.2g"))
  750. a.yaxis.set_major_formatter(FormatStrFormatter("%.2g"))
  751. #t, p = ttest_rel(meanpkwoffs, meanpkwons, nan_policy='omit') # paired t-test
  752. #a.add_artist(AnchoredText('p$=$%.2g' % p, loc='lower right', frameon=False))
  753. """Figure 1S2 FMI plots"""
  754. # scatter plot FMI of all movie measures vs meanrate FMI:
  755. figsize = DEFAULTFIGURESIZE
  756. linmin, linmax, linstep = -1, 1, 1
  757. ticks = np.arange(linmin, linmax+linstep, linstep)
  758. for kind in ['nat']:#MVIKINDS:
  759. for st8 in ['none']:#ALLST8S:
  760. for measure in modmeasuresnoblank:
  761. if measure.startswith('meanrate'):
  762. continue # don't bother plotting meanrate* against meanrate
  763. axislabel = measure2axislabel[measure]
  764. rfmis, msrfmis = [], [] # rate FMIs, measure FMIs
  765. exmplis, exmplmseustrs, normlis = [], [], []
  766. keptmseui = 0 # manually init and increment instead of using enumerate()
  767. for mseustr in mvimseustrs:
  768. rfmi = mviFMI.loc[mseustr, st8]['meanrate']
  769. msrfmi = mviFMI.loc[mseustr, st8][measure]
  770. if pd.isna(rfmi) or pd.isna(msrfmi): # missing at least one FMI value
  771. continue
  772. rfmis.append(rfmi)
  773. msrfmis.append(msrfmi)
  774. if mvimseu2exmpli.get(mseustr) == fig1exmpli:
  775. exmplis.append(keptmseui)
  776. exmplmseustrs.append(mseustr)
  777. else:
  778. normlis.append(keptmseui)
  779. keptmseui += 1 # manually increment
  780. rfmis, msrfmis = np.asarray(rfmis), np.asarray(msrfmis)
  781. ## scatter plot FMIs:
  782. f, a = plt.subplots(figsize=figsize)
  783. wintitle('opto FMI %s vs FMI rate %s %s' % (measure, kind, st8))
  784. # plot x=0 and y=0 lines:
  785. a.axhline(y=0, ls='--', marker='', color='lightgray', zorder=-np.inf)
  786. a.axvline(x=0, ls='--', marker='', color='lightgray', zorder=-np.inf)
  787. # plot normal (non-example) points:
  788. a.scatter(rfmis[normlis], msrfmis[normlis], clip_on=False,
  789. marker='.', c='None', edgecolor=st82clr[st8], s=DEFSZ)
  790. # plot example points, one at a time:
  791. for exmpli, mseustr in zip(exmplis, exmplmseustrs):
  792. marker = exmpli2mrk[mvimseu2exmpli[mseustr]]
  793. c = exmpli2clr[mvimseu2exmpli[mseustr]]
  794. sz = exmpli2sz[mvimseu2exmpli[mseustr]]
  795. lw = exmpli2lw[mvimseu2exmpli[mseustr]]
  796. a.scatter(rfmis[exmpli], msrfmis[exmpli], clip_on=False,
  797. marker=marker, c=c, s=sz, lw=lw)
  798. # get fname of appropriate LMM .cvs file:
  799. if measure == 'meanburstratio': # use Steffen's LMM linregress fit, for fig1S2
  800. fname = os.path.join('stats', 'figure_1_S2c_coefs.csv')
  801. elif measure == 'spars': # use Steffen's LMM linregress fit, for fig1S2
  802. fname = os.path.join('stats', 'figure_1_S2d_coefs.csv')
  803. elif measure == 'rel': # use Steffen's LMM linregress fit, for fig1S2
  804. fname = os.path.join('stats', 'figure_1_S2e_coefs.csv')
  805. elif measure == 'snr': # use Steffen's LMM linregress fit, for fig1S2
  806. fname = os.path.join('stats', 'figure_1_S2f_coefs.csv')
  807. elif measure == 'meanpkw': # use Steffen's LMM linregress fit, for fig1S2
  808. fname = os.path.join('stats', 'figure_1_S2g_coefs.csv')
  809. else:
  810. print("WARNING: No LMM stats for %s measure" % measure)
  811. fname = None
  812. # fetch LMM linregress fit params from .csv:
  813. if fname:
  814. try:
  815. df = pd.read_csv(fname)
  816. foundregression = True
  817. except FileNotFoundError:
  818. print('Missing file: %s' % fname)
  819. foundregression = False
  820. if foundregression:
  821. mm = df['slope'][0]
  822. b = df['intercept'][0]
  823. x = np.array([rfmis.min(), rfmis.max()])
  824. y = mm * x + b
  825. a.plot(x, y, '-', color='red') # plot linregress fit
  826. a.set_xlabel('FR FMI')
  827. if axislabel.islower():
  828. axislabel = axislabel.capitalize()
  829. ylabel = '%s FMI' % axislabel
  830. a.set_ylabel(ylabel)
  831. a.set_xlim(linmin, linmax)
  832. a.set_ylim(linmin, linmax)
  833. a.set_xticks(ticks)
  834. a.set_yticks(ticks)
  835. a.set_aspect('equal')
  836. a.spines['left'].set_position(('outward', 4))
  837. a.spines['bottom'].set_position(('outward', 4))
  838. """Some figure 4S1 plots"""
  839. # scatter plot meanrates of first 2 and last 2 s of movies, limited to first 120 trials
  840. # per condition, as per standard grating experiments:
  841. figsize = DEFAULTFIGURESIZE[0]*1.04, DEFAULTFIGURESIZE[1] # tweak to make space for log units
  842. logmin, logmax = -2, 2
  843. logticks = np.array([-2, 0, 2])
  844. #log0min = logmin + 0.05
  845. kind = 'nat'
  846. st8 = 'none'
  847. for meanratestr, rangestr in zip(['meanrate02', 'meanrate35'], ['0-2', '3-5']):
  848. f, a = plt.subplots(figsize=figsize)
  849. wintitle('opto meanrate movie t=%s s %d trials %s %s' % (rangestr, NTRIALSMVIGRT, kind, st8))
  850. rons, roffs, sgnfs, exmplis, exmplmseustrs, normlis = [], [], [], [], [], []
  851. keptmseui = 0 # manually init and increment instead of using enumerate()
  852. for mseustr in mvimseustrs:
  853. meanrate = mviresp.loc[mseustr, kind, st8][meanratestr]
  854. snr = mviresp.loc[mseustr, kind, st8]['snr']
  855. if meanrate.isna().any(): # missing one or both meanrates
  856. continue
  857. if (snr < SNRTHRESH).all(): # neither condition has decent SNR on the full range
  858. continue
  859. rons.append(meanrate[True])
  860. roffs.append(meanrate[False])
  861. ratesstr = meanratestr.split('mean')[1]+'s'
  862. rates = mviresp.loc[mseustr, kind, st8][ratesstr]
  863. _, pval = ttest_ind(rates[False], rates[True], equal_var=False)
  864. sgnfs.append(pval < SCATTERPTHRESH) # bool
  865. fig1.loc[mseustr, meanratestr] = meanrate[False], meanrate[True] # save
  866. fig1.loc[mseustr][ratesstr] = rates # save trial-wise values
  867. if mvimseu2exmpli.get(mseustr) == fig1exmpli:
  868. exmplis.append(keptmseui)
  869. exmplmseustrs.append(mseustr)
  870. else:
  871. normlis.append(keptmseui)
  872. keptmseui += 1 # manually increment
  873. rons = np.asarray(rons)
  874. roffs = np.asarray(roffs)
  875. sgnfs = np.asarray(sgnfs)
  876. # plot y=x line:
  877. xyline = [10**logmin, 10**logmax], [10**logmin, 10**logmax]
  878. a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1)
  879. insgnfis, = np.where(sgnfs == False)
  880. sgnfis, = np.where(sgnfs == True)
  881. normlinsgnfis = np.intersect1d(normlis, insgnfis)
  882. normlsgnfis = np.intersect1d(normlis, sgnfis)
  883. # plot normal (non-example) insignificant points:
  884. c = desat(st82clr[st8], SGNF2ALPHA[False]) # do manual alpha mixing
  885. a.scatter(rons[normlinsgnfis], roffs[normlinsgnfis], clip_on=False,
  886. marker='.', c='None', edgecolor=c, s=DEFSZ)
  887. # plot normal (non-example) significant points:
  888. c = desat(st82clr[st8], SGNF2ALPHA[True]) # do manual alpha mixing
  889. a.scatter(rons[normlsgnfis], roffs[normlsgnfis], clip_on=False,
  890. marker='.', c='None', edgecolor=c, s=DEFSZ)
  891. # plot normal (non-example) points:
  892. #a.scatter(rons[normlis], roffs[normlis], clip_on=False,
  893. # marker='.', c='None', edgecolor=st82clr[st8], s=DEFSZ)
  894. # plot example points, one at a time:
  895. for exmpli, mseustr in zip(exmplis, exmplmseustrs):
  896. marker = exmpli2mrk[mvimseu2exmpli[mseustr]]
  897. c = exmpli2clr[mvimseu2exmpli[mseustr]]
  898. sz = exmpli2sz[mvimseu2exmpli[mseustr]]
  899. lw = exmpli2lw[mvimseu2exmpli[mseustr]]
  900. a.scatter(rons[exmpli], roffs[exmpli], marker=marker, clip_on=False,
  901. c=c, s=sz, lw=lw)
  902. a.set_xlabel('Suppression FR (spk/s)')
  903. a.set_ylabel('Feedback FR (spk/s)')
  904. a.set_xscale('log')
  905. a.set_yscale('log')
  906. a.set_xlim(10**logmin, 10**logmax)
  907. a.set_ylim(10**logmin, 10**logmax)
  908. a.set_xticks(10.0**logticks)
  909. a.set_yticks(a.get_xticks()) # make log scale y ticks the same as x ticks
  910. a.minorticks_off()
  911. axes_disable_scientific(a)
  912. a.set_aspect('equal')
  913. a.spines['left'].set_position(('outward', 4))
  914. a.spines['bottom'].set_position(('outward', 4))
  915. #t, p = ttest_rel(rons, roffs) # paired t-test
  916. #a.add_artist(AnchoredText('p$=$%.2g' % p, loc='lower right', frameon=False))
  917. #mu = rons.mean(), roffs.mean()
  918. #txt = '$\mathregular{\mu=%.1f, %.1f}$' % mu
  919. #a.add_artist(AnchoredText(txt, loc='upper left', frameon=False))