fig1S6.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. """Figure 1S6 pupil area plots, use run -i fig1S6.py"""
  2. ## Redo scatter plots from fig1.py, but only for movie experiments with insignificant
  3. ## effect of opto on pupil area, as determined by LMM from trial-wise pupil data:
  4. assert EXPTYPE == 'pvmvis'
  5. insigmsefname = os.path.join('stats', 'insig_pupil_diam_exps.csv')
  6. df = pd.read_csv(insigmsefname)
  7. insigmsestrs = list(df['mseustr'].values)
  8. # filter out units from movie experiments with significant opto effects on pupil area:
  9. insigmseustrs = []
  10. for mseustr in mvimseustrs:
  11. mseustrlist = mseustr.split('_')
  12. assert len(mseustrlist) == 6
  13. msestr = '_'.join(mseustrlist[:5]) # drop the unit ID
  14. if msestr in insigmsestrs:
  15. insigmseustrs.append(mseustr)
  16. mvimseustrs = insigmseustrs # overwrite
  17. print("## WARNING: make sure not to save mvimseustrs to disk as a pickle. "
  18. "Its value is overwritten here as a hack")
  19. ## or instead of running this, which generates way too many plots, copy and paste only the
  20. ## meanrate, BR, spars and rel scatter plot code blocks into IPython:
  21. print("Calling fig1.py to generate movie plots")
  22. get_ipython().run_line_magic('run', '-i fig1.py')
  23. plt.show()
  24. print("Now save the first 4 scatter plot figures, but don't save any dataframes")
  25. ## TODO: for reviewer's interest, also calculate average normalized pupil area trace
  26. ## triggered off opto onset, separately for Ntsr and PV
  27. ## scatter plot pupil area during feedback vs suppression, one point (mean over trials) per mse:
  28. for stimtype, stimtypei in zip(STIMTYPESPLUSALL, STIMTYPESPLUSALLI):
  29. linmin, linmax = 0, 0.6
  30. ticks = 0, 0.5
  31. ctrlareas = ipos_opto['mean_area'][:, stimtypei, False].values
  32. optoareas = ipos_opto['mean_area'][:, stimtypei, True].values
  33. f, a = plt.subplots(figsize=DEFAULTFIGURESIZE)
  34. wintitle('pupil %s area opto scatter' % stimtype)
  35. # plot y=x line:
  36. xyline = [linmin, linmax], [linmin, linmax]
  37. a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1)
  38. # plot points:
  39. a.scatter(optoareas, ctrlareas, clip_on=False, marker='.',
  40. c='None', edgecolor='black', s=DEFSZ)
  41. a.set_xlabel('Suppression area (AU)')
  42. a.set_ylabel('Feedback area (AU)')
  43. a.set_xlim(linmin, linmax)
  44. a.set_ylim(linmin, linmax)
  45. a.set_xticks(ticks)
  46. a.set_yticks(ticks)
  47. a.set_aspect('equal')
  48. a.spines['left'].set_position(('outward', 4))
  49. a.spines['bottom'].set_position(('outward', 4))
  50. t, p = ttest_rel(optoareas, ctrlareas) # paired t-test
  51. a.add_artist(AnchoredText('p$=$%.2g' % p, loc='upper left', frameon=False))
  52. ## plot CDFs of pupil area during feedback vs suppression, use trial level precision, one
  53. ## plot per mse:
  54. msestrs = np.unique(ipos_opto.reset_index()['mse'].values)
  55. for msestr in ['PVCre_2017_0006_s03_e03', 'PVCre_2017_0015_s07_e05']:#msestrs:
  56. linmin, linmax = 0, 0.6
  57. ticks = 0, 0.5
  58. ctrlareas = ipos_opto['area_trialmean'][msestr, :, False]
  59. optoareas = ipos_opto['area_trialmean'][msestr, :, True]
  60. assert len(ctrlareas) == 1
  61. assert len(optoareas) == 1
  62. ctrlareas, optoareas = ctrlareas[0], optoareas[0] # pull out of series
  63. f, a = plt.subplots(figsize=DEFAULTFIGURESIZE)
  64. wintitle('pupil area opto CDF %s' % msestr)
  65. a.hist(ctrlareas, bins=np.unique(ctrlareas), density=True, cumulative=True, histtype='step',
  66. color='k', label='V1 Control')
  67. a.hist(optoareas, bins=np.unique(optoareas), density=True, cumulative=True, histtype='step',
  68. color=optoblue, label='V1 Suppressed')
  69. a.set_xlabel('Pupil Area (AU)')
  70. a.set_ylabel('Cumulative probability')
  71. a.set_yticks([0, 0.5, 1])
  72. #a.spines['left'].set_position(('outward', 4))
  73. #a.spines['bottom'].set_position(('outward', 4))
  74. _, ks_p = ks_2samp(optoareas, ctrlareas)
  75. a.add_artist(AnchoredText('p$=$%.2g' % ks_p, loc='upper left', frameon=False))
  76. #l = a.legend(frameon=False)
  77. #l.set_draggable(True)
  78. ## scatter plot firing rate FMI and burst ratio FMI (one value per mseu, y axis)
  79. ## vs pupil area FMI (one value per mse, x axis)
  80. stimtype2FMI = {'mvi':mviFMI, 'grt':grtFMI, 'mvi+grt':pd.concat([mviFMI, grtFMI])}
  81. for stimtype, stimtypei in zip(STIMTYPESPLUSALL, STIMTYPESPLUSALLI):
  82. # first calculate pupil area FMI for each mse:
  83. ipos_opto_stimtype = ipos_opto.loc[(slice(None), stimtypei, slice(None))]
  84. umses = np.unique(ipos_opto_stimtype.reset_index()['mse']) # unique mses for this stimtype
  85. mse2areafmi = {}
  86. for umse in umses:
  87. row = ipos_opto_stimtype.loc[umse]['mean_area'] # indexed by opto
  88. assert len(row) == 2
  89. if stimtype == 'mvi+grt':
  90. row = row.droplevel('stimtype') # drop unitary (redundant) index level
  91. feedback, suppress = row[False], row[True]
  92. areafmi = (feedback - suppress) / (feedback + suppress)
  93. mse2areafmi[umse] = areafmi
  94. # now collect neural FMIs for each mseu:
  95. ## TODO: calculating neural FMIs over all trials, but could also choose only run or sit trials
  96. FMI = stimtype2FMI[stimtype]
  97. st8 = 'none'
  98. mseus = np.unique(FMI.reset_index()['mseu'].values)
  99. rfmis = np.float64(FMI.loc[mseus]['meanrate'][:, st8].values)
  100. brfmis = np.float64(FMI.loc[mseus]['meanburstratio'][:, st8].values)
  101. # get mse string of every mseu in FMI:
  102. mses = np.array(['_'.join(mseu.split('_')[:-1]) for mseu in mseus])
  103. # assign appropriate pupil area FMI to each mseu:
  104. areafmis = np.tile(np.nan, len(mses)) # init to nans
  105. for msei, mse in enumerate(mses):
  106. if mse in mse2areafmi:
  107. areafmis[msei] = mse2areafmi[mse]
  108. ## scatter plot meanrate FMI vs pupil area FMI:
  109. figsize = DEFAULTFIGURESIZE[0]*1.05, DEFAULTFIGURESIZE[1] # tweak to make space for labels
  110. f, a = plt.subplots(figsize=figsize)
  111. wintitle('meanrate %s FMI vs pupil area FMI' % stimtype)
  112. # boolean indicating entries with non-NaN meanrate FMI & pupil area FMI:
  113. valid = ~np.isnan(areafmis) & ~np.isnan(rfmis)
  114. a.scatter(areafmis[valid], rfmis[valid], clip_on=False,
  115. marker='.', c='None', edgecolor='black', s=DEFSZ)
  116. # get fname of appropriate LMM .cvs file:
  117. fname = None
  118. if stimtype == 'mvi+grt':
  119. if EXPTYPE == 'pvmvis':
  120. fname = os.path.join('stats', 'figure_1_S6g_coefs.csv')
  121. elif EXPTYPE == 'ntsrmvis':
  122. fname = os.path.join('stats', 'figure_1_S6h_coefs.csv')
  123. if fname:
  124. try:
  125. df = pd.read_csv(fname)
  126. foundregression = True
  127. except FileNotFoundError:
  128. print('Missing file: %s' % fname)
  129. foundregression = False
  130. if foundregression:
  131. mm = df['slope'][0]
  132. b = df['intercept'][0]
  133. x = np.array([areafmis[valid].min(), areafmis[valid].max()])
  134. y = mm * x + b
  135. a.plot(x, y, '-', color='red') # plot linregress fit
  136. a.set_ylabel("Mean rate FMI")
  137. a.set_xlabel("Pupil area FMI")
  138. xmin, xmax = -0.15, 0.15
  139. ymin, ymax = -1, 1
  140. a.set_xlim(xmin, xmax)
  141. a.set_ylim(ymin, ymax)
  142. a.set_xticks([xmin, 0, xmax])
  143. a.set_yticks([ymin, 0, ymax])
  144. a.spines['left'].set_position(('outward', 4))
  145. a.spines['bottom'].set_position(('outward', 4))
  146. #txt = ('$\mathregular{p=%.2g}$\n' # prob that slope is 0
  147. # '$\mathregular{R^{2}=%.2g}$\n'
  148. # '$\mathregular{slope=%.2g}$' % (p, rsq, mm))
  149. #a.add_artist(AnchoredText(txt, loc='lower left', frameon=False))
  150. ## scatter plot meanburstratio FMI vs pupil area FMI:
  151. f, a = plt.subplots(figsize=figsize)
  152. wintitle('meanburstratio %s FMI vs pupil area FMI' % stimtype)
  153. # boolean indicating entries with non-NaN meanburstratio FMI & pupil area FMI:
  154. valid = ~np.isnan(areafmis) & ~np.isnan(brfmis)
  155. a.scatter(areafmis[valid], brfmis[valid], clip_on=False,
  156. marker='.', c='None', edgecolor='black', s=DEFSZ)
  157. # get fname of appropriate LMM .cvs file:
  158. if stimtype == 'mvi+grt':
  159. if EXPTYPE == 'pvmvis':
  160. fname = os.path.join('stats', 'figure_1_S6i_coefs.csv')
  161. elif EXPTYPE == 'ntsrmvis':
  162. fname = os.path.join('stats', 'figure_1_S6j_coefs.csv')
  163. if fname:
  164. try:
  165. df = pd.read_csv(fname)
  166. foundregression = True
  167. except FileNotFoundError:
  168. print('Missing file: %s' % fname)
  169. foundregression = False
  170. if foundregression:
  171. mm = df['slope'][0]
  172. b = df['intercept'][0]
  173. x = np.array([areafmis[valid].min(), areafmis[valid].max()])
  174. y = mm * x + b
  175. a.plot(x, y, '-', color='red') # plot linregress fit
  176. a.set_ylabel("Burst ratio FMI")
  177. a.set_xlabel("Pupil area FMI")
  178. xmin, xmax = -0.15, 0.15
  179. ymin, ymax = -1, 1
  180. a.set_xlim(xmin, xmax)
  181. a.set_ylim(ymin, ymax)
  182. a.set_xticks([xmin, 0, xmax])
  183. a.set_yticks([ymin, 0, ymax])
  184. a.spines['left'].set_position(('outward', 4))
  185. a.spines['bottom'].set_position(('outward', 4))
  186. #txt = ('$\mathregular{p=%.2g}$\n' # prob that slope is 0
  187. # '$\mathregular{R^{2}=%.2g}$\n'
  188. # '$\mathregular{slope=%.2g}$' % (p, rsq, mm))
  189. #a.add_artist(AnchoredText(txt, loc='upper left', frameon=False))
  190. # save to iposmi dataframe:
  191. if stimtype == 'mvi+grt':
  192. continue # don't overwrite stimtype column in iposmi, other values should be identical
  193. for mseu, areafmi, rfmi, brfmi in zip(mseus, areafmis, rfmis, brfmis):
  194. iposmi.loc[mseu, 'stimtype'] = stimtype # automatically adds a new mseu row if needed
  195. iposmi.loc[mseu, 'areafmi'] = areafmi
  196. iposmi.loc[mseu, 'meanratefmi'] = rfmi
  197. iposmi.loc[mseu, 'meanburstratiofmi'] = brfmi