Scheduled service maintenance on November 22


On Friday, November 22, 2024, between 06:00 CET and 18:00 CET, GIN services will undergo planned maintenance. Extended service interruptions should be expected. We will try to keep downtimes to a minimum, but recommend that users avoid critical tasks, large data uploads, or DOI requests during this time.

We apologize for any inconvenience.

figureConeSupp20190604gin.m 30 KB

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