shadeplot2.m 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. function fhand=shadeplot2(x,y1,y2,varargin)
  2. %
  3. % shadeplot2(x,y1,y2,settings)
  4. % plots two shaded regions without the use of alpha, this allows the renderer to be
  5. % set as painters rather than openGL, giving a vector rather than raster image.
  6. % use shadeplot to quickly view graphs and choose colors, use shadeplot2 for final
  7. % rendered plot.
  8. % calls my_shadeplot over and over again onto the same figure to draw each region
  9. % relies on find_blocks in order to find contiguous regions of overlapping and
  10. % non-overlapping regions.
  11. % relies on mydeal to instantiate variables from structure called "options"
  12. % relies on find_xcross for interpolating between boundaries of overlapping and
  13. % non-overlapping regions.
  14. % x - x vector
  15. % y1 - 2 by x vector, 1st row contains lower bound, 2nd row contains upper bounds
  16. % y2 - "
  17. % options
  18. % .colors - 3x3 matrix, each row is an rgb color for y1, y2, and intersection, respectively
  19. % .fhand - figure handle to plot into, if not specified creates new one
  20. %
  21. % Written by Joseph Jun, 09.23.2008
  22. %
  23. pairs={ 'colors' [0.498*ones(1,3); 0.898*ones(1,3); 0.647*ones(1,3)];...
  24. 'fhand' [];...
  25. };
  26. parseargs(varargin, pairs);
  27. if isempty(fhand)
  28. fhand=axes;
  29. end
  30. if size(x,1)>size(x,2), x=x'; end
  31. if size(y1,1)>size(y1,2), y1=y1'; end
  32. if size(y2,1)>size(y2,2), y2=y2'; end
  33. nx=length(x);
  34. isOverlap=true(1,nx); % true whenever bounds overlap
  35. dy.ll=y1(1,:)-y2(1,:); % the four combinations of differences between lower and upper bounds of curve 1 and 2
  36. dy.lh=y1(1,:)-y2(2,:);
  37. dy.hl=y1(2,:)-y2(1,:);
  38. dy.hh=y1(2,:)-y2(2,:);
  39. blocks.non = dy.lh>0 | dy.hl<0; % all bins where curves do not overlap
  40. blocks.o12 = dy.hh>0 & dy.lh<0 & dy.ll>0; % curves overlap with 1 on top
  41. blocks.o21 = dy.hh<0 & dy.hl>0 & dy.ll<0; % curves overlap with 2 on top
  42. blocks.i12 = dy.hh<=0 & dy.ll>=0; % curves overlap with 1 inside of 2
  43. blocks.i21 = dy.hh>=0 & dy.ll<=0; % curves overlap with 2 inside of 1
  44. % calculate curves of overlapping regions
  45. % c1 and c2 are 1D vectors that define upper (c2) and lower (c1) bounds of overlapped curves
  46. c2(blocks.o12)=y2(2,blocks.o12); % 1 over 2
  47. c1(blocks.o12)=y1(1,blocks.o12);
  48. c2(blocks.o21)=y1(2,blocks.o21); % 2 over 1
  49. c1(blocks.o21)=y2(1,blocks.o21);
  50. c2(blocks.i12)=y1(2,blocks.i12); % 1 inside 2
  51. c1(blocks.i12)=y1(1,blocks.i12);
  52. c2(blocks.i21)=y2(2,blocks.i21); % 2 inside 1
  53. c1(blocks.i21)=y2(1,blocks.i21);
  54. % fill in non-overlapping points for interpolation of boundaries between blocks
  55. temp=blocks.non & dy.lh>=0;
  56. c1(temp)=y1(1,temp);
  57. c2(temp)=y2(2,temp);
  58. temp=blocks.non & dy.hl<=0;
  59. c1(temp)=y2(1,temp);
  60. c2(temp)=y1(2,temp);
  61. hold on;
  62. % -------- first plot y1 then y2 as shade plots
  63. my_shadeplot(x,y1(1,:),y1(2,:),{colors(1,:),fhand,1});
  64. my_shadeplot(x,y2(1,:),y2(2,:),{colors(2,:),fhand,1});
  65. % -------- next plot over the two curves wherever there is an overlap (must be done in blocks)
  66. if sum(~blocks.non)>0
  67. [b,v]=find_blocks(blocks.non); % each row of b has where blocks are, v has whether block is overlapping (false) or non (true)
  68. nb=length(v);
  69. for k=1:nb
  70. if ~v(k)
  71. if sum(b(k,:))>1
  72. my_shadeplot(x(b(k,:)), c1(b(k,:)),c2(b(k,:)), {colors(3,:),fhand,1});
  73. end
  74. end
  75. end
  76. end
  77. % -------- now worry about interpolation inbetween discretization
  78. % ---- first detect any intersection of lines
  79. isll = dy.ll.*[dy.ll(2:end) dy.ll(end)]<0;
  80. islh = dy.lh.*[dy.lh(2:end) dy.lh(end)]<0;
  81. ishl = dy.hl.*[dy.hl(2:end) dy.hl(end)]<0;
  82. ishh = dy.hh.*[dy.hh(2:end) dy.hh(end)]<0;
  83. inds=find(isll | islh | ishl | ishh);
  84. ninds=length(inds);
  85. for k=1:ninds
  86. il=inds(k);
  87. ir=inds(k)+1;
  88. xl=x(il);
  89. xr=x(ir);
  90. templateType=0;
  91. % ---- check to see what kind of overlap exists, create new labeled lines that push
  92. % intersections into templates
  93. if y1(2,il)<y2(1,il)
  94. gy=[y1(1,il) y1(1,ir); y1(2,il) y1(2,ir)];
  95. ry=[y2(1,il) y2(1,ir); y2(2,il) y2(2,ir)];
  96. templateType=1;
  97. elseif y2(2,il)<y1(1,il)
  98. ry=[y1(1,il) y1(1,ir); y1(2,il) y1(2,ir)];
  99. gy=[y2(1,il) y2(1,ir); y2(2,il) y2(2,ir)];
  100. templateType=1;
  101. elseif y1(1,il)>y2(1,il) && y1(1,il)<y2(2,il) && y1(2,il)>y2(2,il)
  102. gy=[y1(1,il) y1(1,ir); y1(2,il) y1(2,ir)];
  103. ry=[y2(1,il) y2(1,ir); y2(2,il) y2(2,ir)];
  104. templateType=2;
  105. elseif y2(1,il)>y1(1,il) && y2(1,il)<y1(2,il) && y2(2,il)>y1(2,il)
  106. ry=[y1(1,il) y1(1,ir); y1(2,il) y1(2,ir)];
  107. gy=[y2(1,il) y2(1,ir); y2(2,il) y2(2,ir)];
  108. templateType=2;
  109. elseif y1(1,il)>y2(1,il) && y1(1,il)<y2(2,il) && y1(2,il)>y2(1,il) && y1(2,il)<y2(2,il)
  110. gy=[y1(1,il) y1(1,ir); y1(2,il) y1(2,ir)];
  111. ry=[y2(1,il) y2(1,ir); y2(2,il) y2(2,ir)];
  112. templateType=3;
  113. elseif y2(1,il)>y1(1,il) && y2(1,il)<y1(2,il) && y2(2,il)>y1(1,il) && y2(2,il)<y1(2,il)
  114. ry=[y1(1,il) y1(1,ir); y1(2,il) y1(2,ir)];
  115. gy=[y2(1,il) y2(1,ir); y2(2,il) y2(2,ir)];
  116. templateType=3;
  117. end
  118. [xll yll]=calc_xcross([xl xr],gy(1,:),[xl xr],ry(1,:));
  119. [xlh ylh]=calc_xcross([xl xr],gy(1,:),[xl xr],ry(2,:));
  120. [xhl yhl]=calc_xcross([xl xr],gy(2,:),[xl xr],ry(1,:));
  121. [xhh yhh]=calc_xcross([xl xr],gy(2,:),[xl xr],ry(2,:));
  122. if xll<xl || xll>xr, xll=[]; yll=[]; end
  123. if xlh<xl || xlh>xr, xlh=[]; ylh=[]; end
  124. if xhl<xl || xhl>xr, xhl=[]; yhl=[]; end
  125. if xhh<xl || xhh>xr, xhh=[]; yhh=[]; end
  126. switch templateType
  127. case 1 % case where green is below red and not intersecting
  128. if isempty(xll)
  129. if isempty(xhh), px=[xhl xr xr]; py=[yhl gy(2,2) ry(1,2)];
  130. else px=[xhl xhh xr xr]; py=[yhl yhh ry(2,2) ry(1,2)];
  131. end
  132. else
  133. if isempty(xhh), px=[xhl xr xr xll]; py=[yhl gy(2,2) gy(1,2) yll];
  134. else
  135. if isempty(xlh), px=[xhl xhh xr xr xll]; py=[yhl yhh ry(2,2) ry(1,2) yll];
  136. else px=[xhl xhh xlh xll]; py=[yhl yhh ylh yll];
  137. end
  138. end
  139. end
  140. case 2 % case where green straddles red from below
  141. if ~isempty(xlh)
  142. px=[xl xl xlh]; py=[gy(1,1) ry(2,1) ylh];
  143. else
  144. if isempty(xll)
  145. px=[xl xl xhh xr xr]; py=[gy(1,1) ry(2,1) yhh gy(2,2) gy(1,2)];
  146. else
  147. if isempty(xhh)
  148. px=[xl xl xr xr xll]; py=[gy(1,1) ry(2,1) ry(2,2) ry(1,2) yll];
  149. else
  150. if isempty(xhl)
  151. px=[xl xl xhh xr xr xll]; py=[gy(1,1) ry(2,1) yhh gy(2,2) ry(1,2) yll];
  152. else
  153. px=[xl xl xhh xhl xll]; py=[gy(1,1) ry(2,1) yhh yhl yll];
  154. end
  155. end
  156. end
  157. end
  158. case 3
  159. if isempty(xhh)
  160. if isempty(xhl)
  161. px=[xl xl xr xr xll]; py=[gy(1,1) gy(2,1) gy(2,2) ry(1,2) yll];
  162. else
  163. px=[xl xl xhl xll]; py=[gy(1,1) gy(2,1) yhl yll];
  164. end
  165. else
  166. if isempty(xll)
  167. if isempty(xlh)
  168. px=[xl xl xhh xr xr]; py=[gy(1,1) gy(2,1) yhh ry(2,2) gy(1,2)];
  169. else
  170. px=[xl xl xhh xlh]; py=[gy(1,1) gy(2,1) yhh ylh];
  171. end
  172. else
  173. px=[xl xl xhh xr xr xll]; py=[gy(1,1) gy(2,1) yhh ry(2,2) ry(1,2) yll];
  174. end
  175. end
  176. end
  177. patch(px,py,colors(3,:),'linestyle','none');
  178. end
  179. % -------- return a VECTOR graphic hurray!
  180. set(gcf,'renderer','painters');
  181. function h=my_shadeplot(x,y1,y2,opt)
  182. % function h=shadeplot(x,y1,y2,opt)
  183. % you need x, sorry
  184. % y1, y2 can be for example lower and upper confidence intervals.
  185. % opt={color, fighandle, alpha}
  186. if nargin <4
  187. h=axes;
  188. clr='k';
  189. alp=0.5;
  190. else
  191. h=opt{2};
  192. alp=opt{3};
  193. clr=opt{1};
  194. end
  195. y2=y2(:)-y1(:);
  196. y1=y1(:);
  197. Y=[y1, y2];
  198. h1=area(h,x,Y);
  199. set(h1(2),'EdgeColor','none','FaceColor',clr);
  200. if ~isempty(alp), alpha(alp); end
  201. set(h1(1),'EdgeColor','none','FaceColor','none');
  202. function [b,v]=find_blocks(x)
  203. %
  204. % [b,v]=find_blocks(x)
  205. % x - single dimensional vector, assumed to be row
  206. % b - boolean matrix containing one row for each discovered block,
  207. % and one column for each element of x, true means that element belongs in the block
  208. %
  209. x=x(:)';
  210. nx=length(x);
  211. cval=x(1);
  212. block_beg=1;
  213. nblocks=0;
  214. if isnumeric(x(end)), x(end+1)=x(end)+1;
  215. else x(end+1)=~x(end);
  216. end
  217. for k=1:(nx+1)
  218. if x(k)~=cval
  219. nblocks=nblocks+1;
  220. b(nblocks,:)=false(1,nx);
  221. b(nblocks,block_beg:(k-1))=true;
  222. block_beg=k;
  223. v(nblocks)=cval;
  224. cval=x(k);
  225. end
  226. end
  227. if block_beg==1, b=true(1,nx); end
  228. v=v';
  229. function [xstar,ystar]=calc_xcross(x,y,u,v)
  230. %
  231. % [xstar,ystar]=calc_xcross(x,y,u,v)
  232. % calculates where two lines cross and value at meeting point
  233. % x - 2 element vector, defines x-coord of 1st line
  234. % y - 2 element vector, defines y-coord of 1st line
  235. % u - 2 element vector, defines x-coord of 2nd line
  236. % v - 2 element vector, defines y-coord of 2nd line
  237. %
  238. y0=(y(1)*x(2)-y(2)*x(1))/(x(2)-x(1));
  239. v0=(v(1)*u(2)-v(2)*u(1))/(u(2)-u(1));
  240. a=(y(2)-y(1))/(x(2)-x(1));
  241. b=(v(2)-v(1))/(u(2)-u(1));
  242. xstar=(y0-v0)/(b-a);
  243. ystar=y0+a*xstar;