fig1S6.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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. ## scatter plot pupil area during feedback vs suppression, one point (mean over trials) per mse:
  26. for stimtype, stimtypei in zip(STIMTYPESPLUSALL, STIMTYPESPLUSALLI):
  27. linmin, linmax = 0, 0.6
  28. ticks = 0, 0.5
  29. ctrlareas = ipos_opto['mean_area'][:, stimtypei, False].values
  30. optoareas = ipos_opto['mean_area'][:, stimtypei, True].values
  31. f, a = plt.subplots(figsize=DEFAULTFIGURESIZE)
  32. wintitle('pupil %s area opto scatter' % stimtype)
  33. # plot y=x line:
  34. xyline = [linmin, linmax], [linmin, linmax]
  35. a.plot(xyline[0], xyline[1], '--', color='gray', zorder=-1)
  36. # plot points:
  37. a.scatter(optoareas, ctrlareas, clip_on=False, marker='.',
  38. c='None', edgecolor='black', s=DEFSZ)
  39. a.set_xlabel('Suppression area (AU)')
  40. a.set_ylabel('Feedback area (AU)')
  41. a.set_xlim(linmin, linmax)
  42. a.set_ylim(linmin, linmax)
  43. a.set_xticks(ticks)
  44. a.set_yticks(ticks)
  45. a.set_aspect('equal')
  46. a.spines['left'].set_position(('outward', 4))
  47. a.spines['bottom'].set_position(('outward', 4))
  48. t, p = ttest_rel(optoareas, ctrlareas) # paired t-test
  49. a.add_artist(AnchoredText('p$=$%.2g' % p, loc='upper left', frameon=False))
  50. ## plot CDFs of pupil area during feedback vs suppression, use trial level precision, one
  51. ## plot per mse:
  52. msestrs = np.unique(ipos_opto.reset_index()['mse'].values)
  53. for msestr in ['PVCre_2017_0006_s03_e03', 'PVCre_2017_0015_s07_e05']:#msestrs:
  54. linmin, linmax = 0, 0.6
  55. ticks = 0, 0.5
  56. ctrlareas = ipos_opto['area_trialmean'][msestr, :, False]
  57. optoareas = ipos_opto['area_trialmean'][msestr, :, True]
  58. assert len(ctrlareas) == 1
  59. assert len(optoareas) == 1
  60. ctrlareas, optoareas = ctrlareas[0], optoareas[0] # pull out of series
  61. f, a = plt.subplots(figsize=DEFAULTFIGURESIZE)
  62. wintitle('pupil area opto CDF %s' % msestr)
  63. a.hist(ctrlareas, bins=np.unique(ctrlareas), density=True, cumulative=True, histtype='step',
  64. color='k', label='V1 Control')
  65. a.hist(optoareas, bins=np.unique(optoareas), density=True, cumulative=True, histtype='step',
  66. color=optoblue, label='V1 Suppressed')
  67. a.set_xlabel('Pupil Area (AU)')
  68. a.set_ylabel('Cumulative probability')
  69. a.set_yticks([0, 0.5, 1])
  70. #a.spines['left'].set_position(('outward', 4))
  71. #a.spines['bottom'].set_position(('outward', 4))
  72. _, ks_p = ks_2samp(optoareas, ctrlareas)
  73. a.add_artist(AnchoredText('p$=$%.2g' % ks_p, loc='upper left', frameon=False))
  74. #l = a.legend(frameon=False)
  75. #l.set_draggable(True)
  76. ## scatter plot firing rate FMI and burst ratio FMI (one value per mseu, y axis)
  77. ## vs pupil area FMI (one value per mse, x axis)
  78. stimtype2FMI = {'mvi':mviFMI, 'grt':grtFMI, 'mvi+grt':pd.concat([mviFMI, grtFMI])}
  79. for stimtype, stimtypei in zip(STIMTYPESPLUSALL, STIMTYPESPLUSALLI):
  80. # first calculate pupil area FMI for each mse:
  81. ipos_opto_stimtype = ipos_opto.loc[(slice(None), stimtypei, slice(None))]
  82. umses = np.unique(ipos_opto_stimtype.reset_index()['mse']) # unique mses for this stimtype
  83. mse2areafmi = {}
  84. for umse in umses:
  85. row = ipos_opto_stimtype.loc[umse]['mean_area'] # indexed by opto
  86. assert len(row) == 2
  87. if stimtype == 'mvi+grt':
  88. row = row.droplevel('stimtype') # drop unitary (redundant) index level
  89. feedback, suppress = row[False], row[True]
  90. areafmi = (feedback - suppress) / (feedback + suppress)
  91. mse2areafmi[umse] = areafmi
  92. # now collect neural FMIs for each mseu:
  93. FMI = stimtype2FMI[stimtype]
  94. st8 = 'none'
  95. mseus = np.unique(FMI.reset_index()['mseu'].values)
  96. rfmis = np.float64(FMI.loc[mseus]['meanrate'][:, st8].values)
  97. brfmis = np.float64(FMI.loc[mseus]['meanburstratio'][:, st8].values)
  98. # get mse string of every mseu in FMI:
  99. mses = np.array(['_'.join(mseu.split('_')[:-1]) for mseu in mseus])
  100. # assign appropriate pupil area FMI to each mseu:
  101. areafmis = np.tile(np.nan, len(mses)) # init to nans
  102. for msei, mse in enumerate(mses):
  103. if mse in mse2areafmi:
  104. areafmis[msei] = mse2areafmi[mse]
  105. ## scatter plot meanrate FMI vs pupil area FMI:
  106. figsize = DEFAULTFIGURESIZE[0]*1.05, DEFAULTFIGURESIZE[1] # tweak to make space for labels
  107. f, a = plt.subplots(figsize=figsize)
  108. wintitle('meanrate %s FMI vs pupil area FMI' % stimtype)
  109. # boolean indicating entries with non-NaN meanrate FMI & pupil area FMI:
  110. valid = ~np.isnan(areafmis) & ~np.isnan(rfmis)
  111. a.scatter(areafmis[valid], rfmis[valid], clip_on=False,
  112. marker='.', c='None', edgecolor='black', s=DEFSZ)
  113. # get fname of appropriate LMM .cvs file:
  114. fname = None
  115. if stimtype == 'mvi+grt':
  116. if EXPTYPE == 'pvmvis':
  117. fname = os.path.join('stats', 'figure_1_S6g_coefs.csv')
  118. elif EXPTYPE == 'ntsrmvis':
  119. fname = os.path.join('stats', 'figure_1_S6h_coefs.csv')
  120. if fname:
  121. try:
  122. df = pd.read_csv(fname)
  123. foundregression = True
  124. except FileNotFoundError:
  125. print('Missing file: %s' % fname)
  126. foundregression = False
  127. if foundregression:
  128. mm = df['slope'][0]
  129. b = df['intercept'][0]
  130. x = np.array([areafmis[valid].min(), areafmis[valid].max()])
  131. y = mm * x + b
  132. a.plot(x, y, '-', color='red') # plot linregress fit
  133. a.set_ylabel("Mean rate FMI")
  134. a.set_xlabel("Pupil area FMI")
  135. xmin, xmax = -0.15, 0.15
  136. ymin, ymax = -1, 1
  137. a.set_xlim(xmin, xmax)
  138. a.set_ylim(ymin, ymax)
  139. a.set_xticks([xmin, 0, xmax])
  140. a.set_yticks([ymin, 0, ymax])
  141. a.spines['left'].set_position(('outward', 4))
  142. a.spines['bottom'].set_position(('outward', 4))
  143. ## scatter plot meanburstratio FMI vs pupil area FMI:
  144. f, a = plt.subplots(figsize=figsize)
  145. wintitle('meanburstratio %s FMI vs pupil area FMI' % stimtype)
  146. # boolean indicating entries with non-NaN meanburstratio FMI & pupil area FMI:
  147. valid = ~np.isnan(areafmis) & ~np.isnan(brfmis)
  148. a.scatter(areafmis[valid], brfmis[valid], clip_on=False,
  149. marker='.', c='None', edgecolor='black', s=DEFSZ)
  150. # get fname of appropriate LMM .cvs file:
  151. if stimtype == 'mvi+grt':
  152. if EXPTYPE == 'pvmvis':
  153. fname = os.path.join('stats', 'figure_1_S6i_coefs.csv')
  154. elif EXPTYPE == 'ntsrmvis':
  155. fname = os.path.join('stats', 'figure_1_S6j_coefs.csv')
  156. if fname:
  157. try:
  158. df = pd.read_csv(fname)
  159. foundregression = True
  160. except FileNotFoundError:
  161. print('Missing file: %s' % fname)
  162. foundregression = False
  163. if foundregression:
  164. mm = df['slope'][0]
  165. b = df['intercept'][0]
  166. x = np.array([areafmis[valid].min(), areafmis[valid].max()])
  167. y = mm * x + b
  168. a.plot(x, y, '-', color='red') # plot linregress fit
  169. a.set_ylabel("Burst ratio FMI")
  170. a.set_xlabel("Pupil area FMI")
  171. xmin, xmax = -0.15, 0.15
  172. ymin, ymax = -1, 1
  173. a.set_xlim(xmin, xmax)
  174. a.set_ylim(ymin, ymax)
  175. a.set_xticks([xmin, 0, xmax])
  176. a.set_yticks([ymin, 0, ymax])
  177. a.spines['left'].set_position(('outward', 4))
  178. a.spines['bottom'].set_position(('outward', 4))
  179. # save to iposmi dataframe:
  180. if stimtype == 'mvi+grt':
  181. continue # don't overwrite stimtype column in iposmi, other values should be identical
  182. for mseu, areafmi, rfmi, brfmi in zip(mseus, areafmis, rfmis, brfmis):
  183. iposmi.loc[mseu, 'stimtype'] = stimtype # automatically adds a new mseu row if needed
  184. iposmi.loc[mseu, 'areafmi'] = areafmi
  185. iposmi.loc[mseu, 'meanratefmi'] = rfmi
  186. iposmi.loc[mseu, 'meanburstratiofmi'] = brfmi