Code covered by the BSD License  

Highlights from
ZoomBox

image thumbnail
from ZoomBox by Doug Hull
Movable, stretchable zoom box in parent axes controls axes limits in all children axes.

zoomBox(hParentAxes, hChildAxes, updateMode)
function zoomBox(hParentAxes, hChildAxes, updateMode)
%ZOOMBOX creates a resizable zoom box.
%   ZOOMBOX(hParentAxes, hChildAxes) will create a resizable zoom box in the
%   parent axes that will cause any number of child axes to be rescaled to
%   the limits of the zoom box.
%
%   ZOOMBOX(hParentAxes, hChildAxes, 1) is intended for large data sets.
%
%   ZOOMBOX(hParentAxes, hChildAxes, 2) is intended for large data sets
%   where the parent axes data has been decimated by the user.
%
%   Update Modes: Third argument
%   0 - [default] updates the children axes as zoom box is moved and
%   resized.  This is recommended for small data sets, but when data sets
%   are large (relative to the power of the machine) the graphics will lag.
%
%   1 - does not update the child axes as the zoom box is moved and resized
%   until the mouse button is released.  This mode also changes all
%   EraseMode property to Xor for all the children of the parent axes.  This is
%   always a quick graphically, but the data in the parent axes may look
%   odd for some data sets.
%
%   2 - same as mode 1 above, with the exception that the EraseMode is not
%   changed to Xor for all the children of the parent axes.  It is assumed
%   that the user will decimate the data in the parent axes on their own.
%   A simple decimation scheme would be to plot every Nth data point:
%   plot(x(1:N:end), y(1:N:end))
%   This will make the graphics faster than mode 0, but not as fast as 1.
%   
%   -1 - removes Zoom Box from all of the listed axes.
%
%   EXAMPLE:
%
%      clear; clc; close all
% 
%      n = 3000; %increase n to emulate a large data set.
%      x  = linspace(0,1,n);
%      y1 = polyval([1 0.3 0.4],x);
%      y2 =     cos(20*x);  
% 
%      hChildAxes(1) = subplot(3,1,1);
%      plot (x,y1,'r-')
% 
%      hChildAxes(2) = subplot(3,1,2);
%      plot (x,y2,'b-')
% 
%      hParentAxes   = subplot(3,1,3);
%      plot (x,y1,'r-',x,y2,'b-')
%      %Some people would decimate the data shown in the parent axes
%      % to save on memory and increase graphics speed.
%      % d = round(n * 1/100); %show every 100th point.
%      % plot (x(1:d:end),y1(1:d:end),'r-',x(1:d:end),y2(1:d:end),'b-')
%
%      %zoomBox(hParentAxes, hChildAxes, 1) %large data set switch on.
%      zoomBox(hParentAxes, hChildAxes)
%
%   ZOOMBOX will create appdata in the curent figure to store the handles of
%   the corners of the zoom box, the handle of the patch which is the zoom
%   box, and the handles of the parent and child axes.  This appdata all
%   starts  with the key letters hZB for "Handle Zoom Box".  Temporary
%   application data is also stored while the mouse button is clicked down,
%   but is removed when released. This also uses the key letters ZB.
%
%   Invoking ZOOMBOX will expand the axis limits on the parent axes by 10%
%   on each side because that works better.  This behavior is controlled by
%   EXPANDAXIS. The zoom box is restricted from getting too close to edges of
%   axes by the helper function restrictPointsToLimits. These behaviors can be
%   changed, but the zoom box might stick to the top of the axes if not
%   careful.
%
%   ZOOMBOX can be used across different figures, inside of GUIs, or
%   multiple times in the same figure, on any number of children axes.
%   However any axes can only be associated with one instance of ZOOMBOX.
%
%   ZOOMBOX uses code from MATLAB Central:
%     MOVEPLOT   by Brandon Kuczenski (modified for this project)
%       MOVEPLOT is no longer used, but was used to bootstrap this project.
%     EXPANDAXIS by Doug Hull

%   ZOOMBOX 2.1- modified to support multiple figures, large data set
%   support, cursors that change with shape to show function, cleaned up
%   the code in general.  Return hold to original state.  Removed
%   dependency on MOVEPLOT by Brandon K. Added some HTML doc.
%
%   Future version will put this code into one monolithic file so easier to
%   use as a feature rather than an application.

%    Doug Hull <hull@mathworks.com>     1/03/2003
%    Copyright 1984-2002 The MathWorks, Inc.
%    This function is not supported by The MathWorks, Inc.
%    It is provided 'as is' without any guarantee of
%    accuracy or functionality.
    
if nargin < 3
    updateMode = 0;
end

if nargin < 2
    error('Input must consist of one axes handle and one vector of axes handles')
end

if ~ishandle([hParentAxes; hChildAxes(:)])
    error('Inputs must be valid axes handles')
end

if ~all(strcmp('axes',get([hParentAxes; hChildAxes(:)],'type')))
    error('Inputs must be valid axes handles')
end

destroyExistingZoomBoxes([hParentAxes; hChildAxes(:)]);

if updateMode == -1
    return %if mode -1 then leave after destroying existing zoomBoxes
end
axis(hParentAxes, 'tight')   %This tightens the  axis so that the zoomBox is
                              %as close to the data as possible.

top    = max(ylim(hParentAxes));
bottom = min(ylim(hParentAxes));
left   = min(xlim(hParentAxes));
right  = max(xlim(hParentAxes));

holdOriginalyOn = ishold;
hold on
hZoomBox = patch([left left right right],[bottom  top top bottom],'y','facecolor','none');

expandaxis % It is nice to have a little extra space around the data in the parent axes.
            % The amount of expansion can be changed here.

hNE    = plot(right, top,    'k.');
hSE    = plot(right, bottom, 'k.');
hSW    = plot(left,  bottom, 'k.');
hNW    = plot(left,  top,    'k.');

if holdOriginalyOn
    hold on;
else
    hold off
end

set(get(hParentAxes,'parent'), 'doublebuffer',  'on')

set(hZoomBox, 'buttonDownFcn', ['zoomBoxButtonDownFcn(' num2str(updateMode) ')']);
set(hZoomBox, 'lineWidth',     2);     

setappdata(hParentAxes, 'hZBcorners',    [hNE, hSE, hSW, hNW]);
setappdata(hParentAxes, 'hZBchildAxes',  hChildAxes);
setappdata(hParentAxes, 'hZBzoomBox',    hZoomBox);

set(get(hParentAxes,'parent'), 'doublebuffer',  'on')

for i = 1 : length(hChildAxes)
    setappdata(hChildAxes(i), 'hZBparentAxes', hParentAxes);
    set(get(hChildAxes(i),'parent'), 'doublebuffer',  'on')
end

moveCorner(hNE, updateMode);
moveCorner(hSE, updateMode);
moveCorner(hSW, updateMode);
moveCorner(hNW, updateMode);

if updateMode == 1
    set(siblings(hNE),'eraseMode','xor')
end

refreshAxesAndZoomBoxFromAppData(hParentAxes);

function flag = isChildAxes(hAxes)

flag = isAppData(hAxes, 'hZBparentAxes');

function flag = isParentAxes(hAxes)

flag = isAppData(hAxes, 'hZBchildAxes');

function flag = isZoomBoxAxes(hAxes)

flag = isChildAxes(hAxes) | isParentAxes(hAxes);

function destroyChildAxes(hChildAxes)

rmappdata(hChildAxes, 'hZBparentAxes');

function destroyParentAxes(hParentAxes)

rmappdata(hParentAxes, 'hZBchildAxes')
delete(getappdata(hParentAxes, 'hZBcorners'));
delete(getappdata(hParentAxes, 'hZBzoomBox'));

function destroyAxesFamily(hAxes)

if isChildAxes(hAxes)
    hParentAxes = getappdata(hAxes      , 'hZBparentAxes');
elseif isParentAxes(hAxes)
    hParentAxes = hAxes;
end

hChildAxes  = getappdata(hAxes, 'hZBchildAxes');

destroyParentAxes(hParentAxes);
for i = 1 : length(hChildAxes)
   destroyChildAxes(hChildAxes(i));
end

function destroyExistingZoomBoxes(hAxesList);

for i = 1 : length(hAxesList)
    if isZoomBoxAxes(hAxesList(i))
        destroyAxesFamily(hAxesList(i));
    end
end
% Copyright 2007 - 2009 The MathWorks, Inc.

Contact us at files@mathworks.com