0001 function theAxis = subplot2(nrows, ncols, thisPlot, varargin)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080 narg = nargin;
0081
0082
0083 isHGUsingMATLABClasses = feature('HGUsingMATLABClasses');
0084
0085
0086 if isHGUsingMATLABClasses && narg >= 4 && ~ischar(nrows)
0087 arg = varargin{1};
0088 if ischar(arg) && strcmpi(arg,'v6')
0089 warning(['MATLAB:', mfilename, ':IgnoringV6Argument'],...
0090 ['Ignoring the ''v6'' argument to %s.',...
0091 ' This will become an error in a future release.'], upper(mfilename));
0092 narg = narg - 1;
0093 varargin(1) = [];
0094 end
0095 end
0096
0097
0098
0099
0100
0101 kill_siblings = 0;
0102 create_axis = true;
0103 move_axis = false;
0104 delay_destroy = false;
0105 useAutoLayout = true;
0106 tol = sqrt(eps);
0107 parent = get(0,'CurrentFigure');
0108 parentfigure = parent;
0109 if ~isempty(parent) && ~isempty(get(parent,'CurrentAxes'))
0110 parent = get(get(parent,'CurrentAxes'),'Parent');
0111 parentfigure = parent;
0112 if ~strcmp(get(parentfigure,'Type'),'figure')
0113 parentfigure = ancestor(parent,'figure');
0114 end
0115 end
0116 pvpairs = {};
0117 preventMove = false;
0118
0119 inset = [.2 .18 .04 0.6];
0120
0121 if narg == 0
0122 nrows = 111;
0123 narg = 1;
0124 end
0125
0126
0127 handle = '';
0128 position = '';
0129 explicitParent = false;
0130 explicitPosition = false;
0131
0132 if narg == 1
0133
0134
0135
0136
0137 code = nrows;
0138
0139
0140 if(ischar(code))
0141 code = str2double(code);
0142 end
0143
0144
0145 if (~isfinite(code))
0146 error(id('SubplotIndexNonFinite'),'Index must be a finite 3-digit number of the format mnp.')
0147 end
0148
0149
0150 if(rem(code,1) > 0)
0151 handle = code;
0152 if ~strcmp(get(handle,'type'),'axes')
0153 error(id('InvalidAxesHandle'),'Requires valid axes handle for input.')
0154 end
0155 create_axis = false;
0156
0157 else
0158
0159 if (code <= 100 || code >= 1000)
0160 error(id('SubplotIndexOutOfRange'),'Index must be a 3-digit number of the format mnp.')
0161 end
0162
0163 thisPlot = rem(code, 10);
0164 ncols = rem( fix(code-thisPlot)/10,10);
0165 nrows = fix(code/100);
0166 if nrows*ncols < thisPlot
0167 error(id('SubplotIndexTooLarge'),'Index exceeds number of subplots.');
0168 end
0169 kill_siblings = 1;
0170 if(code == 111)
0171 create_axis = false;
0172 delay_destroy = true;
0173 else
0174 create_axis = true;
0175 delay_destroy = false;
0176 end
0177 end
0178
0179 elseif narg == 2
0180
0181 if(strcmpi(nrows, 'position'))
0182 pos_size = size(ncols);
0183 if(pos_size(1) * pos_size(2) == 4)
0184 position = ncols;
0185 explicitPosition = true;
0186 else
0187 error(id('InvalidPositionParameter'),...
0188 'Position must be of the form [left bottom width height].')
0189 end
0190 else
0191 error(id('UnknownOption'),'Unknown command option.')
0192 end
0193 kill_siblings = 1;
0194 useAutoLayout = false;
0195
0196 elseif narg == 3
0197
0198
0199 kill_siblings = 1;
0200
0201 elseif narg >= 4
0202 if ~ischar(nrows)
0203 arg = varargin{1};
0204 if ~ischar(arg)
0205
0206 handle = arg;
0207 parent = get(handle,'Parent');
0208 parentfigure = ancestor(handle,'figure');
0209
0210
0211 explicitParent = true;
0212 set(parentfigure,'CurrentAxes',handle);
0213 move_axis = true;
0214 create_axis = false;
0215 if narg >= 5 && strcmpi(varargin{2},'PreventMove')
0216 preventMove = true;
0217 pvpairs = varargin(3:end);
0218 else
0219 pvpairs = varargin(2:end);
0220 end
0221 elseif strncmpi(arg,'replace',1)
0222
0223 kill_siblings = 2;
0224 elseif strcmpi(arg,'align')
0225
0226
0227
0228 useAutoLayout = false;
0229 kill_siblings = 1;
0230 elseif strcmpi(arg,'v6')
0231
0232
0233
0234 warning(['MATLAB:', mfilename, ':DeprecatedV6Argument'],...
0235 ['The ''v6'' argument to %s is deprecated,',...
0236 ' and will no longer be supported in a future release.'], upper(mfilename));
0237 useAutoLayout = false;
0238 kill_siblings = 1;
0239 else
0240
0241 kill_siblings = 1;
0242 pvpairs = varargin;
0243 par = find(strncmpi('Parent',pvpairs(1:2:end),6));
0244 if any(par)
0245
0246
0247 explicitParent = true;
0248 parent = varargin{2*par(1)};
0249 parentfigure = ancestor(parent,'figure');
0250 end
0251 end
0252 else
0253
0254
0255 if(strcmpi(nrows, 'position'))
0256 pos_size = size(ncols);
0257 if(pos_size(1) * pos_size(2) == 4)
0258 position = ncols;
0259 explicitPosition = true;
0260 else
0261 error(id('InvalidPositionParameter'),...
0262 'Position must be of the form [left bottom width height].')
0263 end
0264 else
0265 error(id('UnknownOption'),'Unknown command option.')
0266 end
0267 kill_siblings = 1;
0268 useAutoLayout = false;
0269 pvpairs = [{thisPlot} varargin];
0270 par = find(strncmpi('Parent',pvpairs(1:2:end),6));
0271 if any(par)
0272
0273
0274 explicitParent = true;
0275 parent = pvpairs{2*par(1)};
0276 parentfigure = ancestor(parent,'figure');
0277 end
0278 end
0279 end
0280
0281
0282 if ~isempty(handle) && ~move_axis
0283 parent = get(handle,'Parent');
0284 parentfigure = ancestor(handle,'figure');
0285 set(parentfigure,'CurrentAxes',handle);
0286 else
0287 if isempty(parent),
0288 parent = gcf;
0289 parentfigure = parent;
0290 end
0291 if isempty(position)
0292 if min(thisPlot) < 1
0293 error(id('SubplotIndexTooSmall'),'Illegal plot number.')
0294 elseif max(thisPlot) > ncols*nrows
0295 error(id('SubplotIndexTooLarge'),'Index exceeds number of subplots.');
0296 else
0297
0298 row = (nrows-1) -fix((thisPlot-1)/ncols);
0299 col = rem (thisPlot-1, ncols);
0300
0301
0302
0303 if ~isappdata(parentfigure,'SubplotDefaultAxesLocation')
0304 if ~strcmp(get(parentfigure,'defaultaxesunits'),'normalized')
0305 tmp = axes;
0306 set(tmp,'units','normalized')
0307 def_pos = get(tmp,'position');
0308 delete(tmp)
0309 else
0310 def_pos = get(parentfigure,'DefaultAxesPosition');
0311 end
0312 setappdata(parentfigure,'SubplotDefaultAxesLocation',def_pos);
0313 else
0314 def_pos = getappdata(parentfigure,'SubplotDefaultAxesLocation');
0315 end
0316
0317
0318 rw = max(row)-min(row)+1;
0319 cw = max(col)-min(col)+1;
0320 width = def_pos(3)/(ncols - inset(1) - inset(3));
0321 height = def_pos(4)/(nrows - inset(2) - inset(4));
0322 inset = inset.*[width height width height];
0323 outerpos = [def_pos(1) + min(col)*width - inset(1), ...
0324 def_pos(2) + min(row)*height - inset(2), ...
0325 width*cw height*rw];
0326
0327
0328 if min(col) == 0
0329 inset(1) = def_pos(1);
0330 outerpos(3) = outerpos(1)+outerpos(3);
0331 outerpos(1) = 0;
0332 end
0333 if min(row) == 0,
0334 inset(2) = def_pos(2);
0335 outerpos(4) = outerpos(2)+outerpos(4);
0336 outerpos(2) = 0;
0337 end
0338 if max(col) == ncols-1,
0339 inset(3) = max(0,1-def_pos(1)-def_pos(3));
0340 outerpos(3) = 1-outerpos(1);
0341 end
0342 if max(row) == nrows-1,
0343 inset(4) = max(0,1-def_pos(2)-def_pos(4));
0344 outerpos(4) = 1-outerpos(2);
0345 end
0346
0347
0348 position = [outerpos(1:2) + inset(1:2),...
0349 outerpos(3:4) - inset(1:2) - inset(3:4)];
0350
0351 end
0352 end
0353 end
0354
0355
0356 nextstate = get(parentfigure,'nextplot');
0357
0358 if strncmp(nextstate,'replace',7)
0359 nextstate = 'add';
0360 elseif strncmp(nextstate,'new',3)
0361 kill_siblings = 0;
0362 end
0363
0364 if(kill_siblings)
0365 if delay_destroy
0366 if nargout
0367 error(id('TooManyOutputs'),...
0368 'Function called with too many output arguments.')
0369 else
0370 set(parentfigure,'NextPlot','replace');
0371 return
0372 end
0373 end
0374 sibs = datachildren(parent);
0375 newcurrent = [];
0376 for i = 1:length(sibs)
0377
0378
0379 if(ishghandle(sibs(i),'axes'))
0380 units = get(sibs(i),'Units');
0381 sibpos = get(sibs(i),'Position');
0382
0383
0384 if ~explicitPosition
0385 if isappdata(sibs(i),'LegendColorbarExpectedPosition') && ...
0386 isequal(getappdata(sibs(i),'LegendColorbarExpectedPosition'),get(sibs(i),'Position'))
0387 inset = getappdata(sibs(i),'LegendColorbarOriginalInset');
0388 if isempty(inset)
0389
0390 inset = get(get(sibs(i),'Parent'),'DefaultAxesLooseInset');
0391 end
0392 inset = offsetsInUnits(sibs(i),inset,'normalized',get(sibs(i),'Units'));
0393 if strcmpi(get(sibs(i),'ActivePositionProperty'),'position')
0394 pos = get(sibs(i),'Position');
0395 loose = get(sibs(i),'LooseInset');
0396 opos = getOuterFromPosAndLoose(pos,loose,get(sibs(i),'Units'));
0397 if strcmp(get(sibs(i),'Units'),'normalized')
0398 inset = [opos(3:4) opos(3:4)].*inset;
0399 end
0400 sibpos = [opos(1:2)+inset(1:2) opos(3:4)-inset(1:2)-inset(3:4)];
0401 end
0402 end
0403 end
0404 if ~strcmp(units,'normalized')
0405 sibpos = hgconvertunits(parentfigure,sibpos,units,'normalized',parent);
0406 end
0407 intersect = 1;
0408 if((position(1) >= sibpos(1) + sibpos(3)-tol) || ...
0409 (sibpos(1) >= position(1) + position(3)-tol) || ...
0410 (position(2) >= sibpos(2) + sibpos(4)-tol) || ...
0411 (sibpos(2) >= position(2) + position(4)-tol))
0412 intersect = 0;
0413 end
0414 if intersect
0415
0416
0417
0418
0419
0420
0421
0422
0423 if (kill_siblings == 2)
0424 delete(sibs(i));
0425
0426
0427
0428
0429
0430
0431
0432 elseif (any(abs(sibpos - position) > tol))
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447 if (explicitPosition)
0448 delete(sibs(i));
0449 else
0450
0451
0452
0453 grid = getappdata(parent,'SubplotGrid');
0454
0455
0456
0457
0458
0459 if isempty(grid) || ~any(grid(:) == sibs(i)) || ...
0460 size(grid,1) ~= nrows || size(grid,2) ~= ncols || ...
0461 ~isscalar(row) || ~isscalar(col)
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476 delete(sibs(i));
0477 end
0478 end
0479 end
0480 if ishghandle(sibs(i))
0481
0482 if ~isempty(newcurrent) && ishghandle(newcurrent)
0483 delete(newcurrent);
0484 end
0485 newcurrent = sibs(i);
0486 end
0487 end
0488 end
0489 end
0490 if ~isempty(newcurrent) && ishghandle(newcurrent)
0491 set(parentfigure,'CurrentAxes',newcurrent);
0492 create_axis = false;
0493 end
0494 set(parentfigure,'NextPlot',nextstate);
0495 end
0496
0497
0498 if create_axis
0499 if strcmp(nextstate,'new') && ~explicitParent
0500 parent = figure;
0501 parentfigure = parent;
0502 end
0503 ax = axes('units','normal','Position',position,...
0504 'LooseInset',inset,'Parent',parent);
0505
0506 set(ax,'units',get(double(parentfigure),'defaultaxesunits'))
0507 if useAutoLayout
0508 addAxesToGrid(ax,nrows,ncols,row,col,position);
0509 end
0510 if ~isempty(pvpairs)
0511 set(ax,pvpairs{:});
0512 end
0513 elseif move_axis && ~preventMove
0514 ax = handle;
0515 units = get(handle,'units');
0516 set(handle,'units','normal','Position',position,...
0517 'LooseInset',inset,'Parent',parent);
0518 set(handle,'units',units);
0519 if useAutoLayout
0520 addAxesToGrid(ax,nrows,ncols,row,col,position);
0521 end
0522 if ~isempty(pvpairs)
0523 set(handle,pvpairs{:});
0524 end
0525 else
0526
0527 ax = get(parentfigure,'CurrentAxes');
0528 end
0529
0530
0531 if(nargout > 0)
0532 theAxis = ax;
0533 end
0534
0535
0536 function createListeners(p,axlisth)
0537 setappdata(p,'SubplotListeners',[])
0538 fig = p;
0539 if ~isequal(get(fig,'Type'),'figure')
0540 fig = ancestor(fig,'figure');
0541 end
0542 list = [...
0543 handle.listener(axlisth,findprop(axlisth(1),'Units'), ...
0544 'PropertyPostSet',@axesUnitsPostSet);
0545 handle.listener(axlisth,findprop(axlisth(1),'Units'), ...
0546 'PropertyPreSet',@axesUnitsPreSet);
0547 handle.listener(axlisth,findprop(axlisth(1),'Position'), ...
0548 'PropertyPostSet',@axesMoved);
0549 handle.listener(axlisth,findprop(axlisth(1),'ActivePositionProperty'), ...
0550 'PropertyPreSet',@axesMoved);
0551 handle.listener(axlisth,findprop(axlisth(1),'Parent'), ...
0552 'PropertyPreSet',@axesMoved);
0553 handle.listener(axlisth,'AxisInvalidEvent',{@subplotlayoutInvalid,p});
0554 handle.listener(handle(fig),'FigureUpdateEvent',{@subplotlayout,p})];
0555 for k=1:length(axlisth)
0556 ax = axlisth(k);
0557 if ~isappdata(double(ax),'SubplotDeleteListener')
0558 setappdata(double(ax),'SubplotDeleteListener',...
0559 handle.listener(ax,'ObjectBeingDestroyed', ...
0560 @axesDestroyed));
0561 end
0562 end
0563 setappdata(p,'SubplotListeners',list)
0564
0565
0566
0567
0568
0569
0570 function addAxesToGrid(ax,nrows,ncols,row,col,position)
0571 p = get(ax,'parent');
0572 grid = getappdata(p,'SubplotGrid');
0573 if isempty(grid)
0574 grid = zeros(nrows,ncols);
0575 end
0576 if any(size(grid) ~= [nrows ncols]), return; end
0577 if length(row) ~= 1 || length(col) ~= 1, return; end
0578 if round(row) ~= row || round(col) ~= col, return; end
0579 if grid(row+1,col+1) == ax, return, end
0580 grid(row+1,col+1) = ax;
0581 list = grid(:);
0582 list(list == 0) = [];
0583 list(~ishghandle(list)) = [];
0584 createListeners(p,handle(list));
0585 setappdata(p,'SubplotGrid',grid)
0586 setappdata(ax,'SubplotPosition',position);
0587 subplotlayoutInvalid(handle(ax),[],p);
0588
0589
0590 function removeAxesFromGrid(p,ax)
0591 grid = getappdata(p,'SubplotGrid');
0592 if ~isempty(grid)
0593 n = grid == ax;
0594 if any(n(:))
0595 grid(n) = 0;
0596 list = grid(:);
0597 list(list == 0) = [];
0598 list(~ishghandle(list)) = [];
0599 if isempty(list)
0600 rmappdata(p,'SubplotListeners');
0601 rmappdata(p,'SubplotGrid');
0602 else
0603 setappdata(p,'SubplotGrid',grid);
0604 end
0605 end
0606 end
0607
0608
0609 function axesMoved(hSrc,evdata)
0610 ax = double(evdata.affectedObject);
0611
0612
0613 if (isappdata(ax,'inLayout') && ~isempty(getappdata(ax,'inLayout'))) || ...
0614 isappdata(ax,'LegendColorbarReclaimSpace')
0615 setappdata(ax,'SubplotPosition',get(ax,'Position'));
0616 else
0617 removeAxesFromGrid(get(ax,'Parent'),ax);
0618 end
0619
0620
0621 function axesUnitsPreSet(hSrc,evdata)
0622 ax = double(evdata.affectedObject);
0623 p = get(ax,'Parent');
0624 list = getappdata(p,'SubplotListeners');
0625 if ~isempty(list)
0626 set(list(2:end),'enable','off');
0627 end
0628
0629
0630 function axesUnitsPostSet(hSrc,evdata)
0631 ax = double(evdata.affectedObject);
0632 p = get(ax,'Parent');
0633 list = getappdata(p,'SubplotListeners');
0634 if ~isempty(list)
0635 set(list(2:end),'enable','on');
0636 end
0637
0638
0639 function axesDestroyed(hSrc,evdata)
0640 ax = double(hSrc);
0641 p = get(ax,'Parent');
0642 if strcmp(get(p,'BeingDeleted'),'off')
0643 removeAxesFromGrid(p,ax);
0644 elseif isappdata(p,'SubplotListeners')
0645 rmappdata(p,'SubplotListeners');
0646 rmappdata(p,'SubplotGrid');
0647 end
0648
0649 function str = id(str)
0650 str = ['MATLAB:subplot:' str];
0651
0652
0653
0654
0655 function out = offsetsInUnits(ax,in,from,to)
0656 fig = ancestor(ax,'figure');
0657 par = get(ax,'Parent');
0658 p1 = hgconvertunits(fig,[0 0 in(1:2)],from,to,par);
0659 p2 = hgconvertunits(fig,[0 0 in(3:4)],from,to,par);
0660 out = [p1(3:4) p2(3:4)];
0661
0662
0663
0664
0665
0666 function outer = getOuterFromPosAndLoose(pos,loose,units)
0667 if strcmp(units,'normalized')
0668
0669 w = pos(3)/(1-loose(1)-loose(3));
0670 h = pos(4)/(1-loose(2)-loose(4));
0671 loose = [w h w h].*loose;
0672 end
0673 outer = [pos(1:2)-loose(1:2) pos(3:4)+loose(1:2)+loose(3:4)];