figureCone20190604.m 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  1. function hd = coneAnalysis
  2. % datachoice = 'visual field'; % for main figure
  3. datachoice = 'retina'; % for supplementary figure
  4. warning('off','MATLAB:interp1:UsePCHIP')
  5. % deactivating the following cbrewer warning:
  6. % Warning: INTERP1(...,'CUBIC') will change in a future release. Use INTERP1(...,'PCHIP') instead.
  7. % > In interp1>sanitycheckmethod (line 265)
  8. % In interp1>parseinputs (line 401)
  9. % In interp1 (line 80)
  10. % In interpolate_cbrewer (line 31)
  11. % In cbrewer (line 101)
  12. % In heatmap20180823 (line 21)
  13. % global globalparam
  14. close all
  15. cd(['C:\Users\dehmelt\Dropbox\Documents\MATLAB\', ...
  16. '201808 SphereAnalysis\fromTakeshiBadenlab_180615\5dpf_180628_correctedbug\'])
  17. % Define which character sequences identify the different types of data file.
  18. filestring.all = 'allCones';
  19. filestring.blue = 'Blue';
  20. filestring.green = 'Green';
  21. filestring.red = 'Red';
  22. filestring.uv = 'UV';
  23. % Manually set max. cone density per square mm, as in Zimmermann et al.
  24. maxdensity = 35000;
  25. % Manually select data files, and automatically check their names.
  26. switch datachoice
  27. case 'visual field'
  28. fileselection = {'VisualFieldProjection_Red_8dpf.txt', ...
  29. 'VisualFieldProjection_Green_8dpf.txt','VisualFieldProjection_Blue_8dpf.txt', ...
  30. 'VisualFieldProjection_UV_8dpf.txt','VisualFieldProjection_allCones_8dpf.txt'};
  31. case 'retina'
  32. fileselection = {'DensityinRetina_Red_8dpf.txt', ...
  33. 'DensityinRetina_Green_8dpf.txt','DensityinRetina_Blue_8dpf.txt', ...
  34. 'DensityinRetina_UV_8dpf.txt','DensityinRetina_allCones_8dpf.txt'};
  35. end
  36. occurrence = struct('all',[],'blue',[],'green',[],'red',[],'uv',[]);
  37. for file = 1:numel(fileselection)
  38. occurrence.all = [occurrence.all, ~isempty(strfind(fileselection{file},filestring.all))];
  39. occurrence.blue = [occurrence.blue, ~isempty(strfind(fileselection{file},filestring.blue))];
  40. occurrence.green = [occurrence.green, ~isempty(strfind(fileselection{file},filestring.green))];
  41. occurrence.red = [occurrence.red, ~isempty(strfind(fileselection{file},filestring.red))];
  42. occurrence.uv = [occurrence.uv, ~isempty(strfind(fileselection{file},filestring.uv))];
  43. end
  44. % Check whether each type of file was selected exactly once.
  45. if sum(occurrence.all) == 0
  46. disp(['None of the file names contain the characters ''',filestring.all,'''.'])
  47. elseif sum(occurrence.all) > 1
  48. error(['More than one file name contains the characters ''',filestring.all,'''!'])
  49. else
  50. datafile.all = fileselection{find(occurrence.all)}; %#ok<FNDSB>
  51. end
  52. if sum(occurrence.blue) == 0
  53. disp(['None of the file names contain the characters ''',filestring.blue,'''.'])
  54. elseif sum(occurrence.blue) > 1
  55. error(['More than one file name contains the characters ''',filestring.blue,'''!'])
  56. else
  57. datafile.blue = fileselection{find(occurrence.blue)}; %#ok<FNDSB>
  58. end
  59. if sum(occurrence.green) == 0
  60. disp(['None of the file names contain the characters ''',filestring.green,'''.'])
  61. elseif sum(occurrence.green) > 1
  62. error(['More than one file name contains the characters ''',filestring.green,'''!'])
  63. else
  64. datafile.green = fileselection{find(occurrence.green)}; %#ok<FNDSB>
  65. end
  66. if sum(occurrence.red) == 0
  67. disp(['None of the file names contain the characters ''',filestring.red,'''.'])
  68. elseif sum(occurrence.red) > 1
  69. error(['More than one file name contains the characters ''',filestring.red,'''!'])
  70. else
  71. datafile.red = fileselection{find(occurrence.red)}; %#ok<FNDSB>
  72. end
  73. if sum(occurrence.uv) == 0
  74. disp(['None of the file names contain the characters ''',filestring.uv,'''.'])
  75. elseif sum(occurrence.uv) > 1
  76. error(['More than one file name contains the characters ''',filestring.uv,'''!'])
  77. else
  78. datafile.uv = fileselection{find(occurrence.uv)}; %#ok<FNDSB>
  79. end
  80. % % Fit centres from FitAzimElev20181217.txt:
  81. % leftnormmaxazim = 74.1675;
  82. % leftnormmaxelev = 5.9175;
  83. % leftnormmeanazim = 74.9488;
  84. % leftnormmeanelev = 5.7009;
  85. % leftnormratioazim = 74.9490;
  86. % leftnormratioelev = 5.7007;
  87. % rightnormmaxazim = -72.0633;
  88. % rightnormmaxelev = 7.3858;
  89. % rightnormmeanazim = -71.1931;
  90. % rightnormmeanelev = 7.5766;
  91. % rightnormratioazim = -71.1933;
  92. % rightnormratioelev = 7.5767;
  93. leftazim_body = -80.2647;
  94. leftelev_body = 6.0557;
  95. rightazim_body = +77.0306;
  96. rightelev_body = -1.9776;
  97. % Median eye position, pooled once, from positionAnalysis20181217.m:
  98. leftmedianazim = +6.2450;
  99. rightmedianazim = -9.8760;
  100. leftmeanazim = +5.2455;
  101. rightmeanazim = -9.8840;
  102. leftstdazim = 6.1703;
  103. rightstdazim = 6.5227;
  104. leftsemazim = 0.2472;
  105. rightsemazim = 0.2613;
  106. % Median vertical eye position, from figureVertical20190225.m:
  107. leftmeanelev = 3.4937; % meanmeanposition.UUH(:,:,1);
  108. rightmeanelev = 4.8735; % meanmeanposition.UUH(:,:,2);
  109. % Corrected to eye-centred visual field angles:
  110. leftazim_eye = abs(leftazim_body - leftmeanazim);
  111. leftelev_eye = leftelev_body - leftmeanelev;
  112. rightazim_eye = abs(rightazim_body - rightmeanazim);
  113. rightelev_eye = rightelev_body - rightmeanelev;
  114. % Create one figure panel per file, and all plots on it.
  115. datapresent = fieldnames(datafile);
  116. % Reorder field names to reflect desired arrangement of panels on figure.
  117. datapresent = {datapresent{[4 3 2 5 1]}};
  118. for typeindex = 1:numel(datapresent)
  119. conetype = datapresent{typeindex};
  120. textfile = datafile.(conetype);
  121. switch datachoice
  122. case 'visual field'
  123. conedata = importdata(textfile) * maxdensity;
  124. case 'retina'
  125. conedata = importdata(textfile);
  126. end
  127. switch datachoice
  128. case 'visual field'
  129. conedata = rot90(conedata,3); % so up is at top, anterior to the left
  130. case 'retina'
  131. conedata = rot90(conedata,1); % so up is at bottom, anterior to the right
  132. end
  133. conedata(conedata==0) = NaN; % consider nonzero data only, i.e. from the true area of the retina
  134. switch datachoice
  135. case 'visual field'
  136. % Undo approximate correction by Takeshi, then apply a more precise one:
  137. offsetAzimTakeshi = 8;
  138. offsetElevTakeshi = 5;
  139. offsetAzimAccurate = abs(leftmedianazim);
  140. offsetElevAccurate = leftmeanelev;
  141. resolutionAzim = size(conedata,2)/360;
  142. resolutionElev = size(conedata,1)/180;
  143. discreteShiftAzim = round((offsetAzimTakeshi-offsetAzimAccurate)/resolutionAzim);
  144. discreteShiftElev = round((offsetElevTakeshi-offsetElevAccurate)/resolutionElev);
  145. nandata = NaN(size(conedata));
  146. % Execute shift (min/max sanitise indices in case shift is negative):
  147. nandata(max(1,1-discreteShiftElev):min(end,end-discreteShiftElev), ...
  148. max(1,1-discreteShiftAzim):min(end,end-discreteShiftAzim)) = ...
  149. conedata(max(1,1+discreteShiftElev):min(end,end+discreteShiftElev), ...
  150. max(1,1+discreteShiftAzim):min(end,end+discreteShiftAzim));
  151. % Overwrite original data:
  152. conedata = nandata;
  153. case 'retina'
  154. % Cannot apply correction, as VF filter used by Takeshi is unknown.
  155. end
  156. % cd(['C:\Users\dehmelt\Dropbox\Documents\MATLAB\', ...
  157. % '201808 SphereAnalysis'])
  158. %
  159. % numelevation = size(conedata,1);
  160. % numazimuth = size(conedata,2);
  161. %
  162. % % The following four values represent the coordinates of the four corners
  163. % % of the 2D data sets provided by Baden lab (and are currently unknown).
  164. % elevation.max = 90;
  165. % elevation.min = -90;
  166. % azimuth.max = 180;
  167. % azimuth.min = -180;
  168. % % Build an (NX*NY x 2) array, where NX is the number of azimuth values,
  169. % % NY is the number of elevation values, NX*NY is the total number of data
  170. % % points, and for each data point (each row), the azimuth (column 1) and
  171. % % elevation (column 2) are listed.
  172. % elevation.step = (elevation.max-elevation.min)/(numelevation-1);
  173. % azimuth.step = (azimuth.max-azimuth.min)/(numazimuth-1);
  174. % elevationlist = elevation.max:-elevation.step:elevation.min;
  175. % azimuthlist = azimuth.max:-azimuth.step:azimuth.min;
  176. % predictor = [];
  177. % for k = 1:numazimuth
  178. % predictor = [predictor; ...
  179. % repmat(azimuthlist(k),[numelevation 1]), elevationlist'];
  180. % end
  181. % % One raw data value per data point, might have to be reformatted to match
  182. % % the order in which the list of data azimuths/elevations in "predictor" is
  183. % % being created. Predictor goes top-to-bottom, left-to-right.
  184. % response = conedata(:);
  185. %
  186. % offset = 0;
  187. % amplitude = 1;
  188. % meanazimuth = 90;
  189. % meanelevation = 0;
  190. % concentration = 1;
  191. %
  192. % globalparam.offset = offset;
  193. % globalparam.amplitude = amplitude;
  194. % globalparam.concentration = concentration;
  195. %
  196. %
  197. % figure(1)
  198. % % imagesc(conedata)
  199. % surf(conedata)
  200. % shading flat
  201. % axis square
  202. % colormap(cbrewer('div','PRGn',100))
  203. % hold on
  204. % plot([1,numazimuth],[numelevation/2 numelevation/2],'--w','LineWidth',2)
  205. % plot([numazimuth/2, numazimuth/2],[1,numelevation],'--w','LineWidth',2)
  206. % hold off
  207. % set(gca,'XTick',[1,numazimuth*[1/4,1/2,3/4,1]],'XTickLabel',{180 90 0 -90 -180})
  208. % set(gca,'YTick',[1,numelevation*[1/4,1/2,3/4,1]],'YTickLabel',{90 45 0 -45 -90})
  209. % xlabel('azimuth'),ylabel('elevation'),set(gcf,'Color',[1 1 1])
  210. % dataclim = get(gca,'CLim');
  211. hd.cone.fg = figure(1);
  212. hd.cone.fg.Position = [400 160 1000 700];
  213. % hd.cone.fg.Position = [500 50 540 380];
  214. hd.cone.fg.Color = [1 1 1];
  215. hd.cone.ax(typeindex,1) = axes;
  216. if typeindex < 4
  217. hd.cone.ax(typeindex,1).Position = [.11+(typeindex-1)*.29 .61 hd.cone.fg.Position([4 3])/3500];
  218. else
  219. hd.cone.ax(typeindex,1).Position = [.19+(typeindex-4)*.42 .11 hd.cone.fg.Position([4 3])/3500];
  220. end
  221. az = 0:180/(size(conedata,1)-1):180;
  222. el = -90:180/(size(conedata,2)-1):90;
  223. % conedatanonnan = fliplr(flipud(conedata));
  224. conedatanonnan = conedata;
  225. conedatanonnan(isnan(conedatanonnan)) = 0;
  226. density = conv2(conedatanonnan,fspecial('gaussian',[100 100],3),'same');
  227. % surf(az,el,conv2(conedatanonnan,fspecial('gaussian',[100 100],10),'same'))
  228. % shading flat
  229. hold on
  230. if strcmp(datachoice,'retina') && typeindex == 5 % FD20190829 added as simple correction
  231. density = fliplr(density)
  232. end
  233. imagesc(az,el,density)
  234. % if strcmp(conetype,'all')
  235. % contour(az,el,density,'LevelStep',1e-1,'Color',.5*[1 1 1])
  236. % else
  237. % contour(az,el,density,'LevelStep',3e-2,'Color',.5*[1 1 1])
  238. % end
  239. contourlevels = (.1:.1:1) * max(max(density)); % increments = 10%-of-max.
  240. contour(az,el,density,contourlevels,'Color',.5*[1 1 1]);
  241. hold off
  242. % axis square
  243. % uistack(hd.cone.ax(typeindex,2),'bottom')
  244. % hd.cone.ax(2,2) = copyobj(hd.cone.ax(2,1),hd.cone.fg)
  245. hd.cone.ax(typeindex,1).XLim = [0,180];
  246. hd.cone.ax(typeindex,1).YLim = [-90,90];
  247. oldclim = hd.cone.ax(typeindex,1).CLim;
  248. % climcutoff = .8;
  249. climcutoff = .60;
  250. % climcutoff = 0;
  251. hd.cone.ax(typeindex,1).CLim = [min(oldclim)+climcutoff*(max(oldclim)-min(oldclim)), ...
  252. max(oldclim)];
  253. switch datachoice
  254. case 'visual field'
  255. hd.cone.ax(typeindex,1).XLabel.String = 'azimuth';
  256. hd.cone.ax(typeindex,1).YLabel.String = 'elevation';
  257. case 'retina'
  258. hd.cone.ax(typeindex,1).XLabel.String = 'x (a.u.)';
  259. hd.cone.ax(typeindex,1).YLabel.String = 'y (a.u.)';
  260. end
  261. textfilesplit = strsplit(textfile,'_');
  262. switch textfilesplit{2}
  263. case 'allCones'
  264. densitylabel = 'all cones combined';
  265. case 'Green'
  266. densitylabel = 'green cones (mm^{-2})';
  267. case 'Red'
  268. densitylabel = 'red cones (mm^{-2})';
  269. case 'Blue'
  270. densitylabel = 'blue cones (mm^{-2})';
  271. case 'UV'
  272. densitylabel = 'ultraviolet cones';
  273. end
  274. % switch textfilesplit{2}
  275. % case 'allCones'
  276. % densitylabel = {'retinal density','(any cones)'};
  277. % case 'Green'
  278. % densitylabel = {'retinal density / mm^{-2}','(green cones)'};
  279. % case 'Red'
  280. % densitylabel = {'retinal density','(red cones)'};
  281. % case 'Blue'
  282. % densitylabel = {'retinal density','(blue cones)'};
  283. % case 'UV'
  284. % densitylabel = {'retinal density','(ultraviolet cones)'};
  285. % end
  286. % switch textfilesplit{2}
  287. % case 'allCones'
  288. % densitylabel = 'density (any cones)';
  289. % case 'Green'
  290. % densitylabel = 'density (green cones)';
  291. % case 'Red'
  292. % densitylabel = 'density (red cones)';
  293. % case 'Blue'
  294. % densitylabel = 'density (blue cones)';
  295. % case 'UV'
  296. % densitylabel = 'density (ultraviolet cones)';
  297. % end
  298. hd.cone.ax(typeindex,1).Title.String = densitylabel;
  299. hd.cone.ax(typeindex,1).Box = 'on';
  300. % hd.cone.ax(typeindex,1).XTick = 0:15:180;
  301. % hd.cone.ax(typeindex,1).YTick = -90:15:90;
  302. % hd.cone.ax(typeindex,1).XTickLabel = {0,[],[],45,[],[],90,[],[],135,[],[],180};
  303. % hd.cone.ax(typeindex,1).YTickLabel = {-90,[],[],-45,[],[],0,[],[],45,[],[],90};
  304. % hd.cone.ax(typeindex,1).XTick = 0:45:180;
  305. % hd.cone.ax(typeindex,1).YTick = -90:45:90;
  306. % hd.cone.ax(typeindex,1).XTickLabel = {0,45,90,135,180};
  307. % hd.cone.ax(typeindex,1).YTickLabel = {-90,-45,0,45,90};
  308. hd.cone.ax(typeindex,1).XTick = 0:30:180;
  309. hd.cone.ax(typeindex,1).YTick = -90:30:90;
  310. switch datachoice
  311. case 'visual field'
  312. hd.cone.ax(typeindex,1).XTickLabel = {0,[],[],90,[],[],180};
  313. hd.cone.ax(typeindex,1).YTickLabel = {-90,[],[],0,[],[],90};
  314. case 'retina'
  315. hd.cone.ax(typeindex,1).XTickLabel = {0,[],[],[],[],[],1};
  316. hd.cone.ax(typeindex,1).YTickLabel = {0,[],[],[],[],[],1};
  317. end
  318. hd.cone.ax(typeindex,1).FontSize = 14;
  319. hd.cone.ax(typeindex,1).TitleFontSizeMultiplier = 1;
  320. hd.cone.ax(typeindex,1).TitleFontWeight = 'bold';
  321. % hd.cone.ax(typeindex,1).Title.Interpreter = 'none';
  322. hd.cone.ax(typeindex,1).Title.Interpreter = 'tex';
  323. % [hd.cone.ax(typeindex,1).XLabel.FontSize, ...
  324. % hd.cone.ax(typeindex,1).YLabel.FontSize, ...
  325. % hd.cone.ax(typeindex,1).Title.FontSize, ...
  326. % ha.cone.ax(typeindex,1).FontSize,
  327. hd.cone.ax(typeindex,1).XGrid = 'on';
  328. hd.cone.ax(typeindex,1).YGrid = 'on';
  329. hd.cone.ax(typeindex,1).Layer = 'top';
  330. hold on
  331. plot([0,180],[0,0],'--k')
  332. plot([90,90],[-90,90],'--k')
  333. hold off
  334. % % leftnormmaxazimVF = abs(leftnormmaxazim - leftmedianazim);
  335. % % leftnormmeanazimVF = abs(leftnormmeanazim - leftmedianazim);
  336. % % leftnormratioazimVF = abs(leftnormratioazim - leftmedianazim);
  337. % % rightnormmaxazimVF = abs(rightnormmaxazim - rightmedianazim);
  338. % % rightnormmeanazimVF = abs(rightnormmeanazim - rightmedianazim);
  339. % % rightnormratioazimVF = abs(rightnormratioazim - rightmedianazim);
  340. hold on
  341. hd.cone.ob(1,1) = plot([153,165],[-65,-65],'k');
  342. hd.cone.ob(1,2) = plot([159,159],[-59,-71],'k');
  343. switch datachoice
  344. case 'visual field'
  345. hd.cone.ob(1,3) = text(153,-64.5,'A','HorizontalAlignment','right','VerticalAlignment','middle');
  346. hd.cone.ob(1,4) = text(166,-64.5,'P','HorizontalAlignment','left','VerticalAlignment','middle');
  347. hd.cone.ob(1,5) = text(159.2,-59.5,'U','HorizontalAlignment','center','VerticalAlignment','bottom');
  348. hd.cone.ob(1,6) = text(159.2,-69.5,'D','HorizontalAlignment','center','VerticalAlignment','top');
  349. case 'retina'
  350. hd.cone.ob(1,3) = text(153,-64.5,'P','HorizontalAlignment','right','VerticalAlignment','middle');
  351. hd.cone.ob(1,4) = text(166,-64.5,'A','HorizontalAlignment','left','VerticalAlignment','middle');
  352. hd.cone.ob(1,5) = text(159.2,-59.5,'D','HorizontalAlignment','center','VerticalAlignment','bottom');
  353. hd.cone.ob(1,6) = text(159.2,-69.5,'U','HorizontalAlignment','center','VerticalAlignment','top');
  354. end
  355. hold off
  356. % circle.radius = 40/2;
  357. % circle.xcentre = leftnormmaxazimVF; % pick preferred measure here
  358. % circle.ycentre = leftnormmaxelev; % pick preferred measure here
  359. % circle.x = -circle.radius:.1:circle.radius;
  360. % circle.y = sqrt(circle.x(1)^2-circle.x.^2);
  361. % hold on
  362. % plot([circle.xcentre + circle.x, fliplr(circle.xcentre + circle.x)], ...
  363. % [circle.ycentre + circle.y, circle.ycentre - circle.y],'-','LineWidth',3,'Color',0*[1 1 1])
  364. % plot([circle.xcentre + circle.x, fliplr(circle.xcentre + circle.x)], ...
  365. % [circle.ycentre + circle.y, circle.ycentre - circle.y],'-','LineWidth',2,'Color',1*[1 1 1])
  366. % hold off
  367. % boundary.angle = 64;
  368. % % centre.azimuth = leftnormmaxazimVF;
  369. % % centre.elevation = leftnormmaxelev;
  370. % centre.azimuth = rightazim;
  371. % centre.elevation = rightelev;
  372. % boundary.resolution = .01;
  373. % [boundary.azimuth,boundary.elevation] = ...
  374. % diskBoundary(centre.azimuth,centre.elevation,boundary.angle,boundary.resolution);
  375. % hold on
  376. % plot(boundary.azimuth,boundary.elevation,'-','LineWidth',3,'Color',0*[1 1 1])
  377. % plot(boundary.azimuth,boundary.elevation,'-','LineWidth',2,'Color',1*[1 1 1])
  378. % hold off
  379. boundary.angle = 40;
  380. % centre.azimuth = leftnormmaxazimVF;
  381. % centre.elevation = leftnormmaxelev;
  382. % centre.azimuth = leftazim_body;
  383. % centre.elevation = leftelev_body;
  384. centre.azimuth = abs(leftazim_body);
  385. centre.elevation = leftelev_body;
  386. switch datachoice
  387. case 'retina'
  388. centre.azimuth = 180-centre.azimuth;
  389. centre.elevation = -centre.elevation;
  390. end
  391. switch datachoice
  392. case 'visual field'
  393. boundary.resolution = .01;
  394. [boundary.azimuth,boundary.elevation] = ...
  395. diskBoundary(centre.azimuth,centre.elevation,boundary.angle,boundary.resolution);
  396. hold on
  397. plot(boundary.azimuth,boundary.elevation,'-','LineWidth',3,'Color',0*[1 1 1])
  398. plot(boundary.azimuth,boundary.elevation,'-','LineWidth',2,'Color',1*[1 1 1])
  399. hold off
  400. end
  401. mtp = 'o';
  402. msz = 100;
  403. mec = [0 0 0];
  404. % mfc = [.2 .8 .2];
  405. % mfa = .2;
  406. mfc = 1*[1 1 1];
  407. mfa = .5;
  408. hold on
  409. % hd.cone.ob(1,7) = scatter(rightazim,rightelev,msz,mtp, ...
  410. % 'MarkerEdgeColor',mec,'MarkerFaceColor',mfc,'MarkerFaceAlpha',mfa);
  411. hd.cone.ob(1,8) = scatter(centre.azimuth,centre.elevation,msz,mtp, ...
  412. 'MarkerEdgeColor',mec,'MarkerFaceColor',mfc,'MarkerFaceAlpha',.8);
  413. % hd.cone.ob(1,9) = scatter(leftnormratioazimVF,leftnormratioelev,msz,mtp, ...
  414. % 'MarkerEdgeColor',mec,'MarkerFaceColor',mfc,'MarkerFaceAlpha',mfa);
  415. % hd.cone.ob(1,10) = scatter(rightnormmaxazimVF,rightnormmaxelev,msz,mtp, ...
  416. % 'MarkerEdgeColor',mec,'MarkerFaceColor',mfc,'MarkerFaceAlpha',mfa);
  417. % hd.cone.ob(1,11) = scatter(rightnormmeanazimVF,rightnormmeanelev,msz,mtp, ...
  418. % 'MarkerEdgeColor',mec,'MarkerFaceColor',mfc,'MarkerFaceAlpha',mfa);
  419. % hd.cone.ob(1,12) = scatter(rightnormratioazimVF,rightnormratioelev,msz,mtp, ...
  420. % 'MarkerEdgeColor',mec,'MarkerFaceColor',mfc,'MarkerFaceAlpha',mfa);
  421. hold off
  422. if typeindex == 2 || typeindex == 3
  423. hd.cone.ax(typeindex,1).YLabel.String = [];
  424. hd.cone.ax(typeindex,1).YTickLabel = [];
  425. end
  426. switch conetype
  427. case 'blue'
  428. colormap(hd.cone.ax(typeindex,1),cbrewer('seq','Blues',100))
  429. case 'green'
  430. colormap(hd.cone.ax(typeindex,1),cbrewer('seq','Greens',100))
  431. case 'red'
  432. colormap(hd.cone.ax(typeindex,1),cbrewer('seq','Reds',100))
  433. case 'uv'
  434. colormap(hd.cone.ax(typeindex,1),cbrewer('seq','Purples',100))
  435. case 'all'
  436. colormap(hd.cone.ax(typeindex,1),cbrewer('seq','Greys',100))
  437. end
  438. hd.cone.ax(typeindex,2) = axes;
  439. hd.cone.ax(typeindex,2).Position = hd.cone.ax(typeindex,1).Position + ...
  440. hd.cone.ax(typeindex,1).Position(3) * .28*[1 0 0 0];
  441. hd.cone.cbar(typeindex) = colorbar;
  442. hd.cone.ax(typeindex,2).Colormap = hd.cone.ax(typeindex,1).Colormap;
  443. hd.cone.ax(typeindex,2).CLim = hd.cone.ax(typeindex,1).CLim;
  444. hd.cone.ax(typeindex,2).FontSize = hd.cone.ax(typeindex,1).FontSize;
  445. hd.cone.ax(typeindex,2).Color = 'none';
  446. [hd.cone.ax(typeindex,2).XAxis.Visible,hd.cone.ax(typeindex,2).YAxis.Visible] = deal('off');
  447. % colormap(cbrewer('div','PRGn',100))
  448. end
  449. hd.cone.ax(1,3) = axes;
  450. hd.cone.ax(1,3).Position = [8 0 1 1];
  451. hd.cone.ax(1,3).Color = 'none';
  452. [hd.cone.ax(1,3).XAxis.Visible,hd.cone.ax(1,3).YAxis.Visible] = deal('off');
  453. for typeindex = 1:numel(datapresent)
  454. parentpos = hd.cone.ax(typeindex,1).Position;
  455. xpos = parentpos(1)+parentpos(3)/2;
  456. ypos = parentpos(2)+parentpos(4)*1.128;
  457. hd.cone.ob(3,typeindex) = text(xpos, ypos, 'retinal density / mm^{-2}');
  458. % hd.cone.ob(3,typeindex) = text(xpos, ypos, 'retinal density (µm^{-2})');
  459. hd.cone.ob(3,typeindex).FontWeight = 'normal';
  460. hd.cone.ob(3,typeindex).Interpreter = 'tex';
  461. hd.cone.ob(3,typeindex).FontSize = hd.cone.ax(typeindex,1).FontSize;
  462. hd.cone.ob(3,typeindex).HorizontalAlignment = 'center';
  463. hd.cone.ob(3,typeindex).VerticalAlignment = 'bottom';
  464. end
  465. uistack(hd.cone.ax(1,3),'bottom')
  466. hd.cone.ax(1,4) = axes;
  467. hd.cone.ax(1,4).Position = [0 0 1 1];
  468. hd.cone.ax(1,4).Color = 'none';
  469. [hd.cone.ax(1,4).XAxis.Visible,hd.cone.ax(1,4).YAxis.Visible] = deal('off');
  470. for typeindex = 1:numel(datapresent)
  471. parentpos = hd.cone.ax(typeindex,1).Position;
  472. % xpos = parentpos(1)+parentpos(3)*-.18;
  473. xpos = parentpos(1)+parentpos(3)*-.23;
  474. ypos = parentpos(2)+parentpos(4)*1.30;
  475. % hd.cone.ob(3,typeindex) = text(xpos, ypos, 'retinal density / mm^{-2}');
  476. switch typeindex
  477. case 1
  478. letterstring = 'a';
  479. case 4
  480. letterstring = 'b';
  481. case 5
  482. letterstring = 'c';
  483. otherwise
  484. letterstring = '';
  485. end
  486. hd.cone.ob(4,typeindex) = text(xpos, ypos, letterstring);
  487. hd.cone.ob(4,typeindex).FontWeight = 'bold';
  488. hd.cone.ob(4,typeindex).Interpreter = 'tex';
  489. hd.cone.ob(4,typeindex).FontSize = hd.cone.ax(typeindex,1).FontSize * 18/14;
  490. hd.cone.ob(4,typeindex).HorizontalAlignment = 'right';
  491. hd.cone.ob(4,typeindex).VerticalAlignment = 'top';
  492. end
  493. uistack(hd.cone.ax(1,3),'bottom')
  494. [hd.cone.ax(:,1).TickLength] = deal([0 0]);
  495. % for k = 1:5, hd.cone.cbar(k,1).Position(1) = hd.cone.ax(k,1).Position(1) + .83*hd.cone.ax(k,1).Position(3); end
  496. runtime = clock;
  497. timestring = ['_', ...
  498. num2str(runtime(1),'%.4u'), ...
  499. num2str(runtime(2),'%.2u'), ...
  500. num2str(runtime(3),'%.2u'), ...
  501. '_', ...
  502. num2str(runtime(4),'%.2u'), ...
  503. num2str(runtime(5),'%.2u'), ...
  504. num2str(runtime(6),'%02.0f')];
  505. % savefig(2,['conefigure/',textfilesplit{2},timestring])
  506. % figure(2),print(['conefigure/',textfilesplit{2},timestring],'-depsc')
  507. % % figure(2),print(['conefigure/',textfilesplit{2},timestring],'-dtiff')
  508. % figure(2),print(['conefigure/',textfilesplit{2},timestring],'-dtiffn')
  509. % figure(2),print(['conefigure/',textfilesplit{2},timestring],'-dpng')
  510. end
  511. function [azimuthOut, elevationOut] = diskBoundary(azimuthIn, elevationIn, angleIn, resolutionIn)
  512. centre.azimuth = azimuthIn;
  513. centre.elevation = elevationIn;
  514. border.angle = angleIn / 2; % convert solid angle ("diameter") to "radius"
  515. border.resolution = resolutionIn;
  516. % The following equation describes orthodromic (or "great circle") distance as an angle:
  517. % arccos(sin(centre.elevation)*sin(border.elevation) + ...
  518. % cos(centre.elevation)*cos(border.elevation)*cos(border.azimuth-centre.azimuth)) = angle;
  519. % border.elevation = centre.elevation-border.angle/2 : .1 : centre.elevation+border.angle/2;
  520. intended = -90 : border.resolution : 90;
  521. % intended = (centre.elevation-border.angle) : border.resolution : (centre.elevation+border.angle);
  522. % "auxiliary" elevations are explicitly added to guarantee coverage near top/bottom of circle:
  523. auxiliary = centre.elevation + border.angle*[-1 1];
  524. % border.elevation = unique([intended,auxiliary]);
  525. limit = cosd([centre.elevation-border.angle centre.elevation+border.angle]);
  526. % intended = acosd(min(limit) : border.resolution : max(limit));
  527. % % XXX Not sure why the following line leads to half of the curve segments not being computed...
  528. % intended = [-acosd(0:border.resolution:1),acosd(1-border.resolution:-border.resolution:0)];
  529. % auxiliary = centre.elevation + border.angle*[-1 1];
  530. border.elevation = unique([intended,auxiliary]);
  531. % figure(6)
  532. % plot(intended)
  533. border.azimuth = centre.azimuth + ...
  534. acosd((cosd(border.angle) - sind(centre.elevation)*sind(border.elevation)) ./ ...
  535. (cosd(centre.elevation)*cosd(border.elevation)));
  536. % Eliminate complex elements...
  537. border.azimuth(imag(border.azimuth)~=0) = NaN; % This statement sometimes fails horribly.
  538. % border.azimuth(imag(border.azimuth)>1e-5) = NaN; % This statement is silly, but more stable.
  539. % ...and compute corresponding values for the second half of the boundary.
  540. border.azimuth = [border.azimuth, 2*centre.azimuth-border.azimuth];
  541. border.elevation = [border.elevation, border.elevation];
  542. border.azimuth = mod(border.azimuth+180,360)-180;
  543. % jump = diff(border.azimuth) > 10*border.resolution;
  544. % border.azimuth(jump) = NaN;
  545. % border.elevation(jump) = NaN;
  546. azimuthOut = border.azimuth;
  547. elevationOut = border.elevation;
  548. end
  549. % function combinedvalue = vonmisesfisher2param_centre(param,predictor)
  550. %
  551. % global globalparam
  552. %
  553. % convention = 'CCW';
  554. % dimension = 3;
  555. % radius = 1;
  556. % if size(predictor,2) == 2
  557. % predictor(:,3) = radius*ones(size(predictor(:,1)));
  558. % end
  559. % [x,y,z] = geo2car(predictor(:,1),predictor(:,2),predictor(:,3),convention);
  560. % direction = [x,y,z];
  561. %
  562. % numberofdistributions = 1; % <---
  563. % value = NaN(size(predictor,1),numberofdistributions);
  564. %
  565. % for k = 1:numberofdistributions
  566. %
  567. % meanazimuth = param(2*k-1);
  568. % meanelevation = param(2*k);
  569. %
  570. % offset = globalparam.offset(k);
  571. % amplitude = globalparam.amplitude(k);
  572. % concentration = globalparam.concentration(k);
  573. %
  574. % [meanx,meany,meanz] = geo2car(meanazimuth,meanelevation,radius,convention);
  575. % meandirection = [meanx,meany,meanz];
  576. %
  577. % bessel = concentration / ...
  578. % (2*pi * (exp(concentration) - exp(-concentration)));
  579. %
  580. % normalisation = concentration^(dimension/2 - 1) / ...
  581. % ((2*pi)^(dimension/2) * bessel);
  582. %
  583. % value(:,k) = normalisation * exp(concentration*meandirection*direction')';
  584. % value(:,k) = amplitude * value(:,k) + offset;
  585. %
  586. % badness = fitpenalty(meanazimuth,-180,180) + ...
  587. % fitpenalty(meanelevation,-90,90) + ...
  588. % fitpenalty(amplitude,0,Inf) + ...
  589. % fitpenalty(concentration,0,Inf);
  590. %
  591. % value(:,k) = value(:,k) + 1e3*badness;
  592. %
  593. % end
  594. %
  595. % combinedvalue = sum(value,2);
  596. %
  597. % end
  598. % function penalty = fitpenalty(value,lowerlimit,upperlimit)
  599. %
  600. % factor = 1;
  601. %
  602. % if value < lowerlimit
  603. %
  604. % penalty = factor*(lowerlimit-value).^1;
  605. %
  606. % elseif value > upperlimit
  607. %
  608. % penalty = factor*(value-upperlimit).^1;
  609. %
  610. % else
  611. %
  612. % penalty = 0;
  613. %
  614. % end
  615. %
  616. % end
  617. % function combinedvalue = oneVonMisesFisher(params,predictor)
  618. % %TWOVONMISESFISHER Evaluate two overlapping von Mises-Fisher distributions.
  619. % %
  620. % % VALUE = VONMISESFISHER computes the value of only one(!)
  621. % % spherical (p=3) von Mises-Fisher distributions at the chosen location.
  622. % %
  623. % % It is formatted to match the input/output structure required by the
  624. % % built-in non-linear regression function nlinfit.
  625. %
  626. % convention = 'CW';
  627. % dimension = 3;
  628. % radius = 1;
  629. % if size(predictor,2) == 2
  630. % predictor(:,3) = radius*ones(size(predictor(:,1)));
  631. % end
  632. % [x,y,z] = geo2car(predictor(:,1),predictor(:,2),predictor(:,3),convention);
  633. % direction = [x,y,z];
  634. %
  635. % numberofdistributions = 1; % <-- This is the only difference to "twoVonMisesFisher.m".
  636. % value = NaN(size(predictor,1),numberofdistributions);
  637. %
  638. % for k = 1:numberofdistributions
  639. %
  640. % offset = params(5*k-4);
  641. % amplitude = params(5*k-3);
  642. % meanazimuth = params(5*k-2);
  643. % meanelevation = params(5*k-1);
  644. %
  645. % meanelevation = 25; % HACK!
  646. %
  647. %
  648. % [meanx,meany,meanz] = geo2car(meanazimuth,meanelevation,radius,convention);
  649. % meandirection = [meanx,meany,meanz];
  650. % % meandirection = geo2car([params((-2:-1)+4*k),radius]);
  651. % concentration = params(5*k);
  652. %
  653. % bessel = concentration / ...
  654. % (2*pi * (exp(concentration) - exp(-concentration)));
  655. %
  656. % normalisation = concentration^(dimension/2 - 1) / ...
  657. % ((2*pi)^(dimension/2) * bessel);
  658. %
  659. % value(:,k) = normalisation * exp(concentration*meandirection*direction')';
  660. % value(:,k) = amplitude * value(:,k) + offset;
  661. %
  662. % % HACK to constrain values
  663. % if abs(meanazimuth) > 180 || ...
  664. % abs(meanelevation) > 90 || ...
  665. % amplitude < 0 || ...
  666. % concentration < 0
  667. %
  668. % value(:,k) = 1e10*ones(size(value(:,k)));
  669. %
  670. % end
  671. %
  672. % end
  673. %
  674. % combinedvalue = sum(value,2);
  675. %
  676. % end