Home > atmlab > graphs > plot2axes.m

plot2axes

PURPOSE ^

PLOT2AXES Graphs one set of data with two sets of axes

SYNOPSIS ^

function [ax, h] = plot2axes(varargin)

DESCRIPTION ^

PLOT2AXES Graphs one set of data with two sets of axes

   PLOT2AXES(X, Y, 'Option1', 'Value1', ...) plots X versus Y with secondary
   axes.  The following options are accepted [default values]:

     XLoc ['top']: location of secondary X-axis
     YLoc ['right']: location of secondary Y-axis
     XScale [1]: scaling factor for secondary X-axis (scalar)
     YScale [1]: scaling factor for secondary Y-axis (scalar)
                 
                 XScale and YScale can also be a character string
                 describing the relationship between the 2 axes, such as
                 the equation relating Celsius and Fahrenheit: '5/9*(x-32)'

     XLim [NaN NaN] : XLim in the primary axes (secondary is adjusted
                      accordingly). The default is naturally selected by
                      the plotting function.
     YLim [NaN NaN] : YLim in the primary axes (secondary is adjusted
                      accordingly). The default is naturally selected by
                      the plotting function.

   PLOT2AXES(@FUN, ...) uses the plotting function @FUN instead of PLOT to
   produce the plot.  @FUN should be a function handle to a plotting
   function, e.g. @plot, @semilogx, @semilogy, @loglog ,@stem, etc. that
   accepts the syntax H = FUN(...).  Optional arguments accepted by these
   plotting functions are also allowed (e.g. PLOT2AXES(X, Y, 'r*', ...))

   [AX, H] = PLOT2AXES(...) returns the handles of the primary and
   secondary axes (in that order) in AX, and the handles of the graphic
   objects in H.

   The actual data is plotted in the primary axes.  The primary axes lie
   on top of the secondary axes.  After the execution of this function,
   the primary axes become the current axes.  If the next plot replaces
   the axes, the secondary axes are automatically deleted.

   When you zoom in or out using the toolbar, it would only zoom the
   primary axes, so you should click on the 'Fix Axes' menu at the top of
   the figure to re-adjust the secondary axes limits.

   PLOT2AXES('FixAxes') fixes the secondary limits of all figures created
   using plot2axes.
   
   Example 1:
     x = 0:.1:1;
     y = x.^2 + 0.1*randn(size(x));
     [ax, h] = plot2axes(x, y, 'ro', 'YScale', 25.4);
     title('Length vs Time');
     set(get(ax(1), 'ylabel'), 'string', 'inch');
     set(get(ax(2), 'ylabel'), 'string', 'millimeter');
     xlabel('time (sec)');

   Example 2:
     [ax, h] = plot2axes(x, y, 'ro', 'YScale', '5/9*(x-32)');
     set(get(ax(1), 'ylabel'), 'string', 'Fahrenheit');
     set(get(ax(2), 'ylabel'), 'string', 'Celcius');

 VERSIONS:
   v1.0 - first version
   v1.1 - added option to specify X and Y limits
   v1.2 - remove tick labels for secondary axes if no scaling factors are
          specified. Also, fixed bug in matching the scaling type (linear
          or log).
   v1.3 - added the 'Fix Axes' menu for adjusting the secondary axes limits
          after zooming.
   v1.4 - added the option for specifying an equation for XScale and YScale
          (June 2005)

 Jiro Doke (Inspired by ideas from Art Kuo)
 March 2005

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

DOWNLOAD ^

plot2axes.m

SOURCE CODE ^

0001 function [ax, h] = plot2axes(varargin)
0002 
0003 %PLOT2AXES Graphs one set of data with two sets of axes
0004 %
0005 %   PLOT2AXES(X, Y, 'Option1', 'Value1', ...) plots X versus Y with secondary
0006 %   axes.  The following options are accepted [default values]:
0007 %
0008 %     XLoc ['top']: location of secondary X-axis
0009 %     YLoc ['right']: location of secondary Y-axis
0010 %     XScale [1]: scaling factor for secondary X-axis (scalar)
0011 %     YScale [1]: scaling factor for secondary Y-axis (scalar)
0012 %
0013 %                 XScale and YScale can also be a character string
0014 %                 describing the relationship between the 2 axes, such as
0015 %                 the equation relating Celsius and Fahrenheit: '5/9*(x-32)'
0016 %
0017 %     XLim [NaN NaN] : XLim in the primary axes (secondary is adjusted
0018 %                      accordingly). The default is naturally selected by
0019 %                      the plotting function.
0020 %     YLim [NaN NaN] : YLim in the primary axes (secondary is adjusted
0021 %                      accordingly). The default is naturally selected by
0022 %                      the plotting function.
0023 %
0024 %   PLOT2AXES(@FUN, ...) uses the plotting function @FUN instead of PLOT to
0025 %   produce the plot.  @FUN should be a function handle to a plotting
0026 %   function, e.g. @plot, @semilogx, @semilogy, @loglog ,@stem, etc. that
0027 %   accepts the syntax H = FUN(...).  Optional arguments accepted by these
0028 %   plotting functions are also allowed (e.g. PLOT2AXES(X, Y, 'r*', ...))
0029 %
0030 %   [AX, H] = PLOT2AXES(...) returns the handles of the primary and
0031 %   secondary axes (in that order) in AX, and the handles of the graphic
0032 %   objects in H.
0033 %
0034 %   The actual data is plotted in the primary axes.  The primary axes lie
0035 %   on top of the secondary axes.  After the execution of this function,
0036 %   the primary axes become the current axes.  If the next plot replaces
0037 %   the axes, the secondary axes are automatically deleted.
0038 %
0039 %   When you zoom in or out using the toolbar, it would only zoom the
0040 %   primary axes, so you should click on the 'Fix Axes' menu at the top of
0041 %   the figure to re-adjust the secondary axes limits.
0042 %
0043 %   PLOT2AXES('FixAxes') fixes the secondary limits of all figures created
0044 %   using plot2axes.
0045 %
0046 %   Example 1:
0047 %     x = 0:.1:1;
0048 %     y = x.^2 + 0.1*randn(size(x));
0049 %     [ax, h] = plot2axes(x, y, 'ro', 'YScale', 25.4);
0050 %     title('Length vs Time');
0051 %     set(get(ax(1), 'ylabel'), 'string', 'inch');
0052 %     set(get(ax(2), 'ylabel'), 'string', 'millimeter');
0053 %     xlabel('time (sec)');
0054 %
0055 %   Example 2:
0056 %     [ax, h] = plot2axes(x, y, 'ro', 'YScale', '5/9*(x-32)');
0057 %     set(get(ax(1), 'ylabel'), 'string', 'Fahrenheit');
0058 %     set(get(ax(2), 'ylabel'), 'string', 'Celcius');
0059 %
0060 % VERSIONS:
0061 %   v1.0 - first version
0062 %   v1.1 - added option to specify X and Y limits
0063 %   v1.2 - remove tick labels for secondary axes if no scaling factors are
0064 %          specified. Also, fixed bug in matching the scaling type (linear
0065 %          or log).
0066 %   v1.3 - added the 'Fix Axes' menu for adjusting the secondary axes limits
0067 %          after zooming.
0068 %   v1.4 - added the option for specifying an equation for XScale and YScale
0069 %          (June 2005)
0070 %
0071 % Jiro Doke (Inspired by ideas from Art Kuo)
0072 % March 2005
0073 %
0074 
0075 if nargin < 1
0076   error('Not enough input arguments');
0077 end
0078 
0079 if nargin == 1 & strcmpi(varargin{1}, 'FixAxes')
0080   figsH = findobj('Type', 'figure');
0081   if ~isempty(figsH)
0082     for iFig = 1:length(figsH)
0083       p2a = getappdata(figsH(iFig), 'p2a');
0084       FixAxes([], [], p2a);
0085     end
0086   end
0087   return;
0088 end
0089 
0090 % Default options
0091 options{1} = 'top';       % XLoc
0092 options{2} = 'right';     % YLoc
0093 options{3} = 1;           % XScale
0094 options{4} = 1;           % YScale
0095 options{5} = [NaN NaN];   % XLim
0096 options{6} = [NaN NaN];   % YLim
0097 
0098 opts = {'XLoc', ...
0099     'YLoc', ...
0100     'XScale', ...
0101     'YScale', ...
0102     'XLim', ...
0103     'YLim'};
0104 
0105 var = varargin;
0106 
0107 % Check to see if the first argument is a function handle
0108 if isa(var{1}, 'function_handle');
0109   func = var{1};
0110   var(1) = '';
0111 else
0112   func = @plot;
0113 end
0114 
0115 % Parse through input arguments for options
0116 try
0117   removeID = [];
0118   for iVar = 1:length(var)
0119     if ischar(var{iVar})
0120       id = strmatch(lower(var{iVar}), lower(opts), 'exact');
0121       if ~isempty(id)
0122         options{id} = var{iVar + 1};
0123         removeID = [removeID, iVar, iVar + 1];
0124       end
0125     end
0126   end
0127 catch
0128   error(sprintf('Error parsing options.\n%s\n', lasterr));
0129 end
0130 
0131 % Verify options
0132 if ~ismember(lower(options{1}), {'top', 'bottom'}) | ...
0133     ~ismember(lower(options{2}), {'right', 'left'}) | ...
0134     ~(isnumeric(options{5}) & length(options{5}) == 2) | ...
0135     ~(isnumeric(options{6}) & length(options{6}) == 2)
0136   error('Bad options');
0137 end
0138 
0139 var(removeID) = '';
0140 
0141 ax1 = newplot;
0142 nextplot = get(ax1, 'NextPlot');
0143 
0144 % Plot data
0145 try
0146   h = feval(func, var{:});
0147 catch
0148   error(sprintf('Failed to plot\n%s\n', lasterr));
0149 end
0150 
0151 set(ax1, 'Box', 'off', 'Color', 'none');
0152 
0153 % Create secondary axes on top of primary axes
0154 ax2 = axes('Position', get(ax1, 'Position'), 'Box', 'off');
0155 
0156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0157 % Apply options
0158 if strcmpi(options{1}, 'top') % XLoc
0159   set(ax1, 'XAxisLocation', 'bottom');
0160   set(ax2, 'XAxisLocation', 'top');
0161 else
0162   set(ax1, 'XAxisLocation', 'top');
0163   set(ax2, 'XAxisLocation', 'bottom');
0164 end
0165 
0166 if strcmpi(options{2}, 'right') % YLoc
0167   set(ax1, 'YAxisLocation', 'left');
0168   set(ax2, 'YAxisLocation', 'right');
0169 else
0170   set(ax1, 'YAxisLocation', 'right');
0171   set(ax2, 'YAxisLocation', 'left');
0172 end
0173 
0174 if ~all(isnan(options{5}))  % XLim
0175   set(ax1, 'XLim', options{5});
0176 end
0177 if ~all(isnan(options{6}))  % YLim
0178   set(ax1, 'YLim', options{6});
0179 end
0180 
0181 if ischar(options{3})
0182   tmp = inline(options{3});
0183   set(ax2, 'XLim', tmp(get(ax1, 'XLim')));
0184 else
0185   set(ax2, 'XLim', get(ax1, 'XLim') * options{3})
0186 end
0187 if ischar(options{4})
0188   tmp = inline(options{4});
0189   set(ax2, 'YLim', tmp(get(ax1, 'YLim')));
0190 else
0191   set(ax2, 'YLim', get(ax1, 'YLim') * options{4})
0192 end
0193 
0194 set(ax2, 'XScale', get(ax1, 'XScale'), ...
0195   'YScale', get(ax1, 'YScale'));
0196 
0197 if options{3} == 1 % if there is no scaling, remove tick labels
0198   set(ax2, 'XTickLabel', '');
0199 end
0200 if options{4} == 1 % if there is no scaling, remove tick labels
0201   set(ax2, 'YTickLabel', '');
0202 end
0203 
0204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0205 % Create DeleteProxy objects (an invisible text object) so that the other
0206 % axes will be deleted properly.  <inspired by PLOTYY>
0207 DeleteProxy(1) = text('Parent', ax1, ...
0208   'Visible', 'off', ...
0209   'HandleVisibility', 'off');
0210 DeleteProxy(2) = text('Parent', ax2, ...
0211   'Visible', 'off', ...
0212   'HandleVisibility', 'off', ...
0213   'UserData', DeleteProxy(1));
0214 set(DeleteProxy(1), 'UserData', DeleteProxy(2));
0215 
0216 set(DeleteProxy, 'DeleteFcn', @DelFcn);
0217 
0218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0219 % Switch the order of axes, so that the secondary axes are under the primary
0220 % axes, and that the primary axes become the current axes
0221 ch = get(get(ax1, 'Parent'), 'Children'); % get list of figure children. ax1 and ax2 must exist in this list
0222 i1 = find(ch == ax1);  % find where ax1 is
0223 i2 = find(ch == ax2);  % find where ax2 is
0224 ch([i1, i2]) = [ax2; ax1];  % swap ax1 and ax2
0225 set(get(ax1, 'Parent'), 'Children', ch, 'CurrentAxes', ax1);  % assign the new list of children and set current axes to primary
0226 
0227 % Restore NextPlot property (just in case it was modified)
0228 set([ax1, ax2], 'NextPlot', nextplot);
0229 
0230 % Store axes information
0231 p2a = getappdata(get(ax1, 'Parent'), 'p2a'); if isempty(p2a); p2a = {}; end;
0232 p2a = [p2a;{ax1, ax2, options{3}, options{4}}];
0233 setappdata(get(ax1, 'Parent'), 'p2a', p2a);
0234 % Create 'Fix Axes' button for adjusting the secondary axes limits after
0235 % zooming
0236 hMenu = findobj(get(ax1, 'Parent'), 'Type', 'uimenu', 'Label', 'Fix Axes');
0237 if isempty(hMenu) | ~ishandle(hMenu)
0238   hMenu = uimenu('Parent', get(ax1, 'Parent'), 'Label', 'Fix Axes', 'callback', @FixAxes);
0239 end
0240 
0241 if nargout > 0
0242   ax = [ax1, ax2];
0243 end
0244 
0245 
0246 %%%%%%%%%%%%%%%%%%%%%%%%%
0247 % @DelFcn
0248 function DelFcn(obj, edata)
0249 
0250 try
0251   set(get(obj, 'UserData'), 'DeleteFcn', 'try;delete(get(gcbo, ''UserData''));end');
0252   set(obj, 'UserData', get(get(obj, 'UserData'), 'Parent'));
0253   delete(get(obj,'UserData'));
0254 end
0255 
0256 
0257 %%%%%%%%%%%%%%%%%%%%%%%%%
0258 % @FixAxes
0259 function FixAxes(obj, edata, p2a)
0260 
0261 if nargin < 3
0262   p2a = getappdata(get(obj, 'Parent'), 'p2a');
0263 end
0264 
0265 if ~isempty(p2a)
0266   for iAx = 1:size(p2a, 1)
0267     if ishandle(p2a{iAx, 1}) & ishandle(p2a{iAx, 2})
0268       if ischar(p2a{iAx, 3})
0269         tmp = inline(p2a{iAx, 3});
0270         set(p2a{iAx, 2}, 'XLim', tmp(get(p2a{iAx, 1}, 'XLim')));
0271       else
0272         set(p2a{iAx, 2}, 'XLim', p2a{iAx, 3} * get(p2a{iAx, 1}, 'XLim'));
0273       end
0274       if ischar(p2a{iAx, 4})
0275         tmp = inline(p2a{iAx, 4});
0276         set(p2a{iAx, 2}, 'YLim', tmp(get(p2a{iAx, 1}, 'YLim')));
0277       else
0278         set(p2a{iAx, 2}, 'YLim', p2a{iAx, 4} * get(p2a{iAx, 1}, 'YLim'));
0279       end
0280     end
0281   end
0282 end

Generated on Mon 15-Sep-2014 13:31:28 by m2html © 2005