PlotTuningCurve.m 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. function [target_window,circle_r] = PlotTuningCurve(ev,ts,cnd,varargin)
  2. %PlotTuningCurve(ev, ts , cnd,varargin)
  3. % Functions for ploting tuning curve, the ev is the event time, ts is the
  4. % spike's timestamp
  5. %
  6. iod = @utils.inputordefault;
  7. pre = iod('pre',0,varargin);
  8. post = iod('post',1,varargin);
  9. binsz = iod('binsz',0.01,varargin);
  10. krn = iod('krn',0.1,varargin);
  11. tar_pre = iod('tar_pre',0.25,varargin);
  12. tar_post = iod('tar_post',0.25,varargin);
  13. target_time = iod('target_time',[],varargin);% the time point as the center of the tuning curve time window
  14. clr = iod('color',[0 0 0],varargin);
  15. titlestr = iod('titlestr',[],varargin);
  16. sub_cnd = iod('sub_cnd',[],varargin);
  17. r_lim = iod('rlim',[],varargin);
  18. isplot = iod('isplot',1,varargin);
  19. savedir = iod('savedir',[],varargin);
  20. cellid = iod('cellid',0,varargin);
  21. ax = iod('ax',[],varargin);
  22. circle_r = iod('circle_r',[],varargin);
  23. [headlength,varargin]=iod('headlength',3,varargin);
  24. [headstyle,varargin]=iod('headstyle','cback3',varargin);
  25. [linewidth,varargin] = iod('linewidth',2,varargin);
  26. if iscell(cnd)
  27. %cnd_nan = cellfun(@(x)isnan(x), cnd);
  28. cnd_nan = cellfun(@(x)strcmp(x,'null'), cnd);
  29. %cnd(cnd_nan) = 'NaN';
  30. cnd = categorical(cnd);
  31. n_cnd = categories(cnd);
  32. else
  33. cnd = categorical(cnd);
  34. n_cnd = categories(cnd);
  35. end
  36. if ~isempty(sub_cnd) && iscell(cnd)
  37. %cnd_nan = cellfun(@(x)isnan(x), cnd);
  38. sub_cnd_nan = cellfun(@(x)strcmp(x,'null'), sub_cnd);
  39. %cnd(cnd_nan) = 'NaN';
  40. sub_cnd = categorical(sub_cnd);
  41. n_sub_cnd = categories(sub_cnd);
  42. else
  43. sub_cnd = categorical(sub_cnd);
  44. n_sub_cnd = categories(sub_cnd);
  45. end
  46. if isscalar(krn)
  47. dx=ceil(5*krn);
  48. kx=-dx:binsz:dx;
  49. krn=normpdf(kx,0, krn);
  50. if isempty(find(kx==0, 1))
  51. error('Your binsz needs to divide 1 second into interger # of bins');
  52. end
  53. krn(kx<0)=0;
  54. krn=krn/sum(krn);
  55. end
  56. [Y,x]=stats.spike_filter(ev,ts,krn,'pre',pre,'post',post,'kernel_bin_size',binsz);
  57. % [refY,x] = stats.spike_filter(ref_ev,ts,krn,'pre',pre,'post',post,'kernel_bin_size',binsz);
  58. ymn = nan(numel(n_cnd),numel(x));
  59. for ci=1:numel(n_cnd)
  60. ref=cnd==n_cnd(ci);
  61. y=Y(ref,:);
  62. ymn(ci,:) = nanmean(y,1);
  63. end
  64. if isempty(target_time) %is the user is not prividing target_time for doing tuning curve, we find a time window with maxinum variance
  65. % take nanvar?
  66. [~,I] = sort(nanvar(ymn));
  67. target_time = x(I(end));
  68. end
  69. target_window = [max([x(1),target_time-tar_pre]),min([x(end),target_time+tar_post])];
  70. % get firing rate in the target_window
  71. tar_fr = nan(numel(n_cnd),1);
  72. tar_se = nan(numel(n_cnd),1);
  73. for ci = 1:numel(n_cnd)
  74. ref = cnd==n_cnd(ci);
  75. tar_fr(ci) = nanmean(stats.qcount(ts,ev(ref)+target_window(1),ev(ref)+target_window(2))./(target_window(2)-target_window(1)));
  76. tar_se(ci) = nanstd(stats.qcount(ts,ev(ref)+target_window(1),ev(ref)+target_window(2))./(target_window(2)-target_window(1)))/(nansum(ref)^0.5);
  77. end
  78. if isempty(sub_cnd)
  79. angles = cellfun(@(x)utils.ExtractAngleInfo('MidC',cellstr(x),'Rat'), n_cnd);
  80. else
  81. angles = cellfun(@(x,y)utils.ExtractAngleInfo(cellstr(x),cellstr(y),'Rat'), n_cnd,{n_sub_cnd{1};n_sub_cnd{2};n_sub_cnd{1};n_sub_cnd{2}});
  82. end
  83. [~ ,sort_index]=sort(angles);% angles from MidR, counterclockwise
  84. sort_index = [sort_index;sort_index(1)];
  85. theta = angles(sort_index);
  86. [x1, y1] = pol2cart(theta, tar_fr(sort_index)); % Convert To Cartesian
  87. vecsum = nanmean([x1,y1],1);
  88. [x2, y2] = pol2cart(theta, tar_fr(sort_index)-tar_se(sort_index));
  89. [x3,y3] = pol2cart(theta,tar_fr(sort_index)+tar_se(sort_index));
  90. [~,temp] = max(tar_fr(sort_index));
  91. max_theta = theta(temp);
  92. if isplot
  93. if isempty(ax)
  94. ax = draw.jaxes();
  95. else
  96. axes(ax);
  97. end
  98. hold on;
  99. if isempty(circle_r)
  100. circle_r = ceil(nanmax(abs(tar_fr))*1.1);
  101. end
  102. lim = circle_r;% axis limits
  103. set(gca,'XTickLabel',[],'YTickLabel',[],'XTick',[],'YTick',[],'XColor','none','YColor','none','XLim',[-lim lim],'YLim',[-lim lim]);
  104. % start plotting
  105. draw_circle(ax,0,0,circle_r);
  106. draw_lines(ax,0,0,angles,circle_r,headstyle,linewidth,headlength);
  107. p_out = patch(x3,y3,clr + [0.8 0.8 0.8], 'EdgeColor','none') ; % Outer std % Fill Area Between Radius Limits
  108. p_in = patch(x2,y2,[1 1 1],'EdgeColor','none');% Inner std
  109. p_mean = plot(x1, y1, '-o','MarkerSize',2,'MarkerFaceColor',clr,'MarkerEdgeColor',clr,'Color',clr); %mean line
  110. text(0,-lim,[titlestr,' ',num2str(circle_r),' Hz '],'HorizontalAlignment','center','VerticalAlignment','bottom');
  111. else
  112. h = nan;
  113. end
  114. if ~isempty(savedir)
  115. print('-dpdf','-r300',figh, fullfile(savedir,sprintf('tune.cell.%d.pdf',cellid)));
  116. saveas(figh, fullfile(savedir,sprintf('tune.cell.%d.png',cellid)));
  117. end
  118. end
  119. function draw_circle(ax,x,y,r)
  120. %x and y are the coordinates of the center of the circle
  121. %r is the radius of the circle
  122. %0.01 is the angle step, bigger values will draw the circle faster but
  123. %you might notice imperfections (not very smooth)
  124. ang=0:0.01:2*pi;
  125. xp=r*cos(ang);
  126. yp=r*sin(ang);
  127. plot(ax,x+xp,y+yp,'Color','k');
  128. plot(ax,x,y,'Color','k'); % Center of the Circle
  129. end
  130. function draw_lines(ax,x,y,angles,r,headstyle,linewidth,headlength)
  131. ax_left = ax.Position(1);
  132. ax_bot = ax.Position(2);
  133. ax_wid = ax.Position(3);
  134. ax_hei = ax.Position(4);
  135. xp = r.* cos(angles);
  136. yp = r.* sin(angles);
  137. for ii = 1:6
  138. clr = draw.get_dirpos_clrs(utils.ang2name(angles(ii)));
  139. x_start = (x+xp(ii)*0.9-ax.XLim(1))/(ax.XLim(2)-ax.XLim(1))*ax_wid+ax_left;
  140. x_end = (x+xp(ii)*1.2-ax.XLim(1))/(ax.XLim(2)-ax.XLim(1))*ax_wid+ax_left;
  141. y_start = (y+yp(ii)*0.9-ax.YLim(1))/(ax.YLim(2)-ax.YLim(1))*ax_hei+ax_bot;
  142. y_end = (y+yp(ii)*1.2-ax.YLim(1))/(ax.YLim(2)-ax.YLim(1))*ax_hei+ax_bot;
  143. annotation('arrow',[x_start,x_end],[y_start,y_end],'Color',clr{1},'HeadStyle',headstyle,'LineWidth',linewidth,'HeadLength',headlength,'HeadWidth',5);
  144. end
  145. end