Code covered by the BSD License

### Harry Lee (view profile)

12 Nov 2005 (Updated )

Add multiple y-axes to plots. zoomable with zoom modification.

### Editor's Notes:

This file was selected as MATLAB Central Pick of the Week

buttonupfcn2D(hZoom, cpMulAxes)
```function buttonupfcn2D(hZoom, cpMulAxes)
%MOUSEBTNUPFCN Mouse button up function

% Copyright 2003-2004 The MathWorks, Inc.

% This code originates from simulink zoom.

% This constant specifies the number of pixels the mouse
% must move in order to do a rbbox zoom.
POINT_MODE_MAX_PIXELS = 5; % pixels

% Get necessary handles
hFig = get(hZoom,'FigureHandle');
hLines     = get(hZoom,'LineHandles');
currentAxes = get(hZoom,'CurrentAxes');

% Get net mouse movement in pixels
orig_units = get(hFig,'Units');
set(hFig,'Units','Pixels');
fp = get(hFig,'CurrentPoint');
set(hFig,'Units',orig_units);
orig_fp = get(hZoom,'MousePoint');
dpixel = abs(orig_fp-fp);

% The first point of line 1 is always the zoom origin.
XDat   = get(hLines(1), 'XData');
YDat   = get(hLines(1), 'YData');
origin = [XDat(1), YDat(1)];

% Loop through all the currentAxes and zoom-in each of them
for k = 1:length(currentAxes),
cAx = currentAxes(k);

isPointMode = false;

% cpMulAxes is the zoom origin for multiple axes if any.
if k > 1
origin = cpMulAxes(k-1,:);
end

% Get the current limits.
currentXLim = get(cAx, 'XLim');
newXLim = currentXLim;
currentYLim = get(cAx, 'YLim');
newYLim = currentYLim;

% Perform zoom operation based on zoom mode.
switch(get(hZoom,'Constraint')),
case 'none',
%
% Both x and y zoom.
% RBBOX - lines:
%
%          2
%    o-------------
%    |            |
%  1 |            | 4
%    |            |
%    --------------
%          3
%

% Determine the end point of zoom operation.

% Get current point.
cp = get(cAx, 'CurrentPoint'); cp = cp(1,1:2);
xcp = cp(1);
ycp = cp(2);

% Uncomment to clip rbbox zoom to current axes limits
%if xcp > currentXLim(2),
%    xcp = currentXLim(2);
%end
%if xcp < currentXLim(1),
%    xcp = currentXLim(1);
%end
%if ycp > currentYLim(2),
%    ycp = currentYLim(2);
%end
%if ycp < currentYLim(1),
%    ycp = currentYLim(1);
%end

endPt = [xcp ycp];

% Determine the mode: POINT or RBBOX.
if (dpixel(1) <= POINT_MODE_MAX_PIXELS) ...
&& (dpixel(2) <= POINT_MODE_MAX_PIXELS)
isPointMode = true;
end
newXLim(k,:) = localGetNewXLim(cAx,k,isPointMode,xcp,origin,endPt);
newYLim(k,:) = localGetNewYLim(cAx,k,isPointMode,ycp,origin,endPt);

case 'horizontal',
% x only zoom.
% RBBOX - lines (only 1-3 used):
%
%    |     1      |
%  2 o------------| 3
%    |            |
%
%

% Determine the end point of zoom operation.
cp = get(cAx, 'CurrentPoint'); cp = cp(1,1:2);
xcp = cp(1);

% Uncomment to clip rbbox zoom to current axes limits
% if xcp > currentXLim(2),
%    xcp = currentXLim(2);
% end
% if xcp < currentXLim(1),
%    xcp = currentXLim(1);
% end

endPt = [xcp origin(2)];

% Determine mode: POINT or RBBOX.
if dpixel(1)  <= POINT_MODE_MAX_PIXELS
isPointMode = true;
end

newXLim(k,:) = localGetNewXLim(cAx,k,isPointMode,xcp,origin,endPt);
newYLim(k,:) = currentYLim;

case 'vertical',
% y only zoom.
% RBBOX - lines (only 1-3 used):
%    2
%  --o--
%    |
%  1 |
%    |
%  -----
%    3
%

% Determine the end point of zoom operation.

% End pt is the 2nd point of line 1.
cp = get(cAx, 'CurrentPoint'); cp = cp(1,1:2);
ycp = cp(2);

% Uncomment to clip rbbox zoom to current axes limits
% if ycp > currentYLim(2),
%    ycp = currentYLim(2);
% end
% if ycp < currentYLim(1),
%    ycp = currentYLim(1);
% end

endPt = [origin(1) ycp];

% Determine mode: POINT or RBBOX.
if dpixel(2) <= POINT_MODE_MAX_PIXELS
isPointMode = true;
end

newYLim(k,:) = localGetNewYLim(cAx,k,isPointMode,ycp,origin,endPt);
newXLim(k,:) = currentXLim;

end % switch

% Actual zoom operation
%========================================================
%  Part of modification for ADDAXIS commands
ystart = get(gca,'ylim');
%========================================================
axis(cAx,[newXLim(k,:),newYLim(k,:)]);
%====================================================================
%  This is a modification to accomodate the ADDAXIS commands.
%  Check to see if add axis has been used and update the axes using
%  the same scale factors.  (also put ystart = get(gca,'ylim');
%  before the zoom is started above)

yend = get(gca,'ylim');

%  ystart and yend are the starting and ending yaxis limits
%  now go through all of the added axes and scale their limits
%axh = get(gca,'userdata');
if ~isempty(axh)
for I = 1:length(axh)
axhan = axh{I}(1);
axyl = get(axhan,'ylim');
axylnew(1) = axyl(1)+(yend(1)-ystart(1))/(ystart(2)-ystart(1)).*...
(axyl(2)-axyl(1));
axylnew(2) = axyl(2)-(ystart(2)-yend(2))/(ystart(2)-ystart(1)).*...
(axyl(2)-axyl(1));
set(axhan,'ylim',axylnew);
end
end

%  END of modification
%================================================================

end % for

% Delete the RBBOX lines.
if ishandle(hLines)
scribefiglisten(hFig,'off');
delete(hLines);
scribefiglisten(hFig,'on');
end

% Call drawnow to flush axes update since the next line, create2Dundo,
% will take a long time when called for the first time (class loading).
drawnow expose

if length(currentAxes)==1
% This runs slow the first time due to UDD class loading
create2Dundo(hZoom,cAx,[currentXLim,currentYLim],[newXLim(k,:),newYLim(k,:)]);
end

%----------------------------------------------------%
function [newXLim] = localGetNewXLim(hAxes,k,isPointMode,xcp,origin,endPt)
% ToDo: clean up input arguments

% Calculate the new X-Limits.
if ~isPointMode % Bounding Box Mode.
x_lim = [origin(1) endPt(1)];
if x_lim(1) > x_lim(2),
x_lim = x_lim([2 1]);
end
else % Point Mode.
% Divide the vertical into 5 divisions.
x_lim = get(hAxes, 'XLim');
if strcmp(get(hAxes, 'XScale'), 'log'),
diff_log = diff(log10(x_lim))/5;
xcp_log = log10(xcp);
xmin = 10.^(xcp_log-diff_log);
xmax = 10.^(xcp_log+diff_log);
x_lim = [xmin,xmax];
else
XDiff = (x_lim(2) - x_lim(1)) / 5;
x_lim = [xcp - XDiff, xcp + XDiff];
end
end

% Set new Xlimits.
% NOTE: Check that the limits aren't equal.  This happens
%   at very small limits.  In this case, we do nothing.
%
if abs(x_lim(1) - x_lim(2)) > 1e-10*(abs(x_lim(1)) + abs(x_lim(2)))
newXLim(k,:) = x_lim;
else
newXLim = xlim(hAxes);
end

%----------------------------------------------------%
function [newYLim] = localGetNewYLim(hAxes,k,isPointMode,ycp,origin,endPt)
% ToDo: clean up input arguments

% Calculate the new Y-Limits.
if ~isPointMode % Bounding Box Mode.
y_lim = [origin(2) endPt(2)];
if y_lim(1) > y_lim(2),
y_lim = y_lim([2 1]);
end
else % Point Mode.
% Divide the vertical into 5 divisions.
y_lim = get(hAxes, 'YLim');
if strcmp(get(hAxes, 'YScale'), 'log'),
diff_log = diff(log10(y_lim))/5;
ycp_log = log10(ycp);
ymin = 10.^(ycp_log-diff_log);
ymax = 10.^(ycp_log+diff_log);
y_lim = [ymin,ymax];
else
YDiff = (y_lim(2) - y_lim(1)) / 5;
y_lim = [ycp - YDiff, ycp + YDiff];
end
end

% Set new Ylimits.
% NOTE: Check that the limits aren't equal.  This happens
%   at very small limits.  In this case, we do nothing.
%
if abs(y_lim(1) - y_lim(2)) > 1e-10*(abs(y_lim(1)) + abs(y_lim(2)))
newYLim(k,:) = y_lim;
else
newYLim = ylim(hAxes);
end

```