diff m-toolbox/classes/@ao/iplot.m @ 0:f0afece42f48

Import.
author Daniele Nicolodi <nicolodi@science.unitn.it>
date Wed, 23 Nov 2011 19:22:13 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m-toolbox/classes/@ao/iplot.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,2576 @@
+% IPLOT provides an intelligent plotting tool for LTPDA.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% DESCRIPTION: IPLOT provides an intelligent plotting tool for LTPDA.
+%
+% CALL:               hfig = iplot (a,pl)
+%              [hfig, hax] = iplot (a,pl)
+%         [hfig, hax, hli] = iplot (a,pl)
+%
+% INPUTS:      pl   - a parameter list
+%              a    - input analysis object
+%
+% OUTPUTS:     hfig - handles to figures
+%              hax  - handles to axes
+%              hli  - handles to lines
+%
+% AO Plot Info
+% ------------
+%
+% If an input AO has a filled plotinfo plist, then the options contained in
+% therein will overide any other options. The recognised keys are:
+%
+%   'linestyle', 'linewidth', 'color', 'marker', 'legend_on'
+%
+% The possible values are all those accepted by plot.
+%
+%
+% Notes on Parameters
+% -------------------
+%
+%        Many of the properties take cell-array values. If the length of
+%        the cell array is shorter than the number of lines to plot, the
+%        remaining lines will be plotted with the default options. If the
+%        cell array is of length 2 and the first cell contains the string
+%        'all', then the second cell is used to set the propery of all
+%        lines.
+%
+%
+% Error parameters: If you give more than one input AO then you must
+%                   specify the following parameter values in a cell-array,
+%                   one cell for each input AO. Leave the cell empty to
+%                   plot no errors. Each error can be a value or a vector
+%                   the same length as the data vector. If you give and
+%                   upper limit but not lower limit, then the errors are
+%                   assumed to be symmetric (and vice versa)
+%
+%
+% EXAMPLES:
+%
+% 1) Plot two time-series AOs with different colors, line styles, and widths
+%
+%   pl = plist('Linecolors', {'g', 'k'}, 'LineStyles', {'None', '--'}, 'LineWidths', {1, 4});
+%   iplot(tsao1, tsao2, pl);
+%
+% 2) Plot two time-series AOs in subplots. Also override the second legend
+%    text and the first line style.
+%
+%   pl = plist('Arrangement', 'subplots', 'LineStyles', {'--'}, 'Legends', {'', 'My Sine Wave'});
+%   iplot(tsao1, tsao2, pl);
+%
+%
+% 3) Plot two frequency-series AOs on subplots with the same Y-scales and
+%    Y-ranges
+%
+%   pl1 = plist('Yscales', {'All', 'lin'});
+%   pl2 = plist('arrangement', 'subplots', 'YRanges', {'All', [1e-6 100]});
+%   iplot(fsd1, fsd2, pl1, pl2)
+%
+% <a href="matlab:utils.helper.displayMethodInfo('ao', 'iplot')">Parameters Description</a>
+%
+% VERSION:     $Id: iplot.m,v 1.142 2011/08/15 06:08:28 hewitson Exp $
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% DEPRECATED xmaths and ymaths in release 2.4
+
+% 3) Plot two time-series AOs taking the square of the y-values of the
+%    first AO and the log of the x-values of the second AO.
+%
+%   pl = plist('Arrangement', 'subplots', 'YMaths', 'y.^2', 'XMaths', {'', 'log(x)'});
+%   iplot(tsao1, tsao2, pl);
+
+% Math operations: You can specify rudimentary math operations to be
+%                  performed on the X and Y data prior to plotting. The
+%                  'all' keyword is also supported by these parameters.
+%
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% TODO:
+%    1) Add XRange, YRange, ZRange to xyzdata
+%
+
+function varargout = iplot(varargin)
+  
+  import utils.const.*
+  
+  %% Check if this is a call for parameters
+  if utils.helper.isinfocall(varargin{:})
+    varargout{1} = getInfo(varargin{3});
+    return
+  end
+  
+  utils.helper.msg(msg.PROC3, 'running %s/%s', mfilename('class'), mfilename);
+  
+  % Collect input variable names
+  in_names = cell(size(varargin));
+  for ii = 1:nargin,in_names{ii} = inputname(ii);end
+  
+  % Collect all AOs and plists
+  [as, ao_invars] = utils.helper.collect_objects(varargin(:), 'ao', in_names);
+  [upl, pl_invars] = utils.helper.collect_objects(varargin(:), 'plist', in_names);
+  if numel(upl)>1, upl = combine(upl); end
+  
+  %% Go through AOs and collect them into similar types
+  
+  tsAOs  = [];
+  fsAOs  = [];
+  xyAOs  = [];
+  xyzAOs = [];
+  cAOs   = [];
+  
+  consistent = 1;
+  for jj = 1:numel(as)
+    % Check if AOs are consistent (all containing data of the same class):
+    if ~strcmpi(class(as(jj).data) , class(as(1).data) ), consistent = 0; end;
+    switch class(as(jj).data)
+      case 'tsdata'
+        if isempty(as(jj).y)
+          warning('AO %s has no data and will not be plotted', as(jj).name);
+        else
+          tsAOs = [tsAOs as(jj)]; %#ok<*AGROW>
+        end
+      case 'fsdata'
+        if isempty(as(jj).y)
+          warning('AO %s has no data and will not be plotted', as(jj).name);
+        else
+          fsAOs = [fsAOs as(jj)];
+        end
+      case 'xydata'
+        if isempty(as(jj).y)
+          warning('AO %s has no data and will not be plotted', as(jj).name);
+        else
+          xyAOs = [xyAOs as(jj)];
+        end
+      case 'xyzdata'
+        if isempty(as(jj).y)
+          warning('AO %s has no data and will not be plotted', as(jj).name); %#ok<*WNTAG>
+        else
+          xyzAOs = [xyzAOs as(jj)];
+        end
+      case 'cdata'
+        if isempty(as(jj).y)
+          warning('AO %s has no data and will not be plotted', as(jj).name);
+        else
+          cAOs = [cAOs as(jj)];
+        end
+      otherwise
+        warning('!!! Unknown data type %s', class(as(jj).data));
+    end
+  end
+  
+  
+  %% Now plot all the objects on separate figures
+  %  (unless they're consistent and a figure handle was passed)
+  
+  if consistent && ~isempty(upl), fig2plot = find(upl,'Figure'); else fig2plot = []; end
+  
+  hfig = [];
+  hax  = [];
+  hli  = [];
+  
+  %----------- TSDATA
+  if ~isempty(tsAOs)
+    % get default plist
+    dpl = getDefaultPlist('Time-series plot');
+    % combine the plists
+    pl = parse(upl, dpl);
+    % Call x-y plot
+    [hf, ha, hl] = xy_plot(tsAOs, pl, fig2plot);
+    hfig = [hfig hf];
+    hax  = [hax ha];
+    hli  = [hli hl];
+  end
+  %----------- XYDATA
+  if ~isempty(xyAOs)
+    % get default plist
+    dpl = getDefaultPlist('X-Y data plot');
+    % combine the plists
+    pl = parse(upl, dpl);
+    % Call x-y plot
+    [hf, ha, hl] = xy_plot(xyAOs, pl, fig2plot);
+    hfig = [hfig hf];
+    hax  = [hax ha];
+    hli  = [hli hl];
+  end
+  %----------- XYZDATA
+  if ~isempty(xyzAOs)
+    % get default plist
+    dpl = getDefaultPlist('3D plot');
+    % combine the plists
+    pl = parse(upl, dpl);
+    % Call x-y-z plot
+    [hf, ha, hl] = xyz_plot(xyzAOs, pl, fig2plot);
+    hfig = [hfig hf];
+    hax  = [hax ha];
+    hli  = [hli hl];
+  end
+  %----------- CDATA
+  if ~isempty(cAOs)
+    % get default plist
+    dpl = getDefaultPlist('Y data plot');
+    % combine the plists
+    pl = parse(upl, dpl);
+    % Call x-y plot
+    [hf, ha, hl] = y_plot(cAOs, pl, fig2plot);
+    hfig = [hfig hf];
+    hax  = [hax ha];
+    hli  = [hli hl];
+  end
+  %----------- FSDATA
+  if ~isempty(fsAOs)
+    % get default plist
+    dpl = getDefaultPlist('Frequency-series plot');
+    % combine the plists
+    pl = parse(upl, dpl);
+    % Call fsdata plot
+    [hf, ha, hl] = fs_plot(fsAOs, pl, fig2plot);
+    hfig = [hfig hf];
+    hax  = [hax ha];
+    hli  = [hli hl];
+  end
+  
+  %% Deal with outputs
+  if nargout == 1
+    varargout{1} = hfig;
+  end
+  if nargout == 2
+    varargout{1} = hfig;
+    varargout{2} = hax;
+  end
+  if nargout == 3
+    varargout{1} = hfig;
+    varargout{2} = hax;
+    varargout{3} = hli;
+  end
+  
+  if nargout > 3
+    error('### Incorrect number of outputs');
+  end
+  
+end
+
+%--------------------------------------------------------------------------
+% Plot fsdata objects
+%
+function varargout = fs_plot(varargin)
+  
+  aos = varargin{1};
+  pl  = varargin{2};
+  fig2plot = varargin{3};
+  
+  UseLatex = find(pl, 'LatexLabels');
+  if ischar(UseLatex)
+    UseLatex = eval(UseLatex);
+  end
+  
+  % Extract parameters
+  arrangement     = find(pl, 'Arrangement');
+  colors          = find(pl, 'Colors');
+  linecolors      = find(pl, 'LineColors');
+  linestyles      = find(pl, 'LineStyles');
+  markers         = find(pl, 'Markers');
+  linewidths      = find(pl, 'LineWidths');
+  legends         = find(pl, 'Legends');
+  legendsFont     = find(pl, 'LegendFontSize');
+  ylabels         = find(pl, 'YLabels');
+  xlabels         = find(pl, 'XLabels');
+  yscales         = find(pl, 'YScales');
+  xscales         = find(pl, 'XScales');
+  yranges         = find(pl, 'YRanges');
+  xranges         = find(pl, 'XRanges');
+  xmaths          = find(pl, 'XMaths');
+  ymaths          = find(pl, 'YMaths');
+  type            = find(pl, 'Function');
+  legendLoc       = find(pl, 'LegendLocation');
+  complexPlotType = find(pl, 'complexPlotType');
+  autoErrors      = find(pl, 'AUTOERRORS');
+  
+  % Convert the colour if it is a character to a cell-string
+  if ischar(colors)
+    colors = cellstr(colors);
+  end
+  
+  % get errors
+  XerrL       = find(pl, 'XerrL');
+  XerrU       = find(pl, 'XerrU');
+  YerrL       = find(pl, 'YerrL');
+  YerrU       = find(pl, 'YerrU');
+  if ~iscell(XerrU), XerrU = {XerrU}; end
+  if ~iscell(XerrL), XerrL = {XerrL}; end
+  if ~iscell(YerrU), YerrU = {YerrU}; end
+  if ~iscell(YerrL), YerrL = {YerrL}; end
+  if (numel(XerrL) > 1 && numel(XerrL) ~= numel(aos)) || ...
+      (numel(YerrL) > 1 && numel(YerrL) ~= numel(aos)) || ...
+      (numel(XerrU) > 1 && numel(XerrU) ~= numel(aos)) || ...
+      (numel(YerrU) > 1 && numel(YerrU) ~= numel(aos))
+    error('### Please specify 1 set of errors for all AOs, or a set of errors for each AO.');
+  end
+  
+  % check whether we want legends or not
+  if iscell(legends)
+    legendsOn = 1;
+  else
+    if strcmpi(legends, 'off')
+      legendsOn = 0;
+    else
+      legendsOn = 1;
+      legends = [];
+    end
+  end
+  
+  if ~isempty(ymaths) || ~isempty(xmaths)
+    warning('The use of the ''ymaths'' and ''xmaths'' parameters is deprecated. Please perform any calculations before calling iplot.');
+  end
+  
+  if ~iscell(linewidths), linewidths = {linewidths}; end
+  if ~iscell(linestyles), linestyles = {linestyles}; end
+  if ~iscell(linecolors), linecolors = {linecolors}; end
+  if ~iscell(markers), markers = {markers}; end
+  if ~iscell(legends), legends = {legends}; end
+  if ~iscell(ylabels), ylabels = {ylabels}; end
+  if ~iscell(xlabels), xlabels = {xlabels}; end
+  if ~iscell(xmaths), xmaths = {xmaths}; end
+  if ~iscell(ymaths), ymaths = {ymaths}; end
+  if ~iscell(xscales), xscales = {xscales}; end
+  if ~iscell(yscales), yscales = {yscales}; end
+  if ~iscell(xranges), xranges = {xranges}; end
+  if ~iscell(yranges), yranges = {yranges}; end
+  
+  % collect figure handles
+  fsfig = []; fsax  = []; fsli  = [];
+  % Legend holder
+  legendStrR = [];
+  legendStrI = [];
+  % Helper variables
+  ymin = Inf;
+  ymax = -Inf;
+  xmin = Inf;
+  xmax = -Inf;
+  complexFig   = [];
+  complexAxes  = [];
+  
+  if ~isempty(aos)
+    % Now loop over AOs
+    Na = length(aos);
+    % First to check if any are complex y data including any Y maths at the same
+    % time.
+    haveComplex = 0;
+    for jj = 1:Na
+      % Get data
+      y = aos(jj).data.getY;
+      % Do any math operations
+      ymath = parseOptions(jj, ymaths, 'y');
+      eval(sprintf('y = %s;', ymath));
+      % Is this a complex plot?
+      if ~isreal(y)
+        haveComplex = 1;
+      end
+    end
+    
+    % Do we want to use a unit placeholder on the yaxis?
+    yunits = aos(1).data.yunits;
+    yunitPlaceholder = '[Mixed]';
+    useYunitPlaceholder = false;
+    if strcmpi(arrangement, 'stacked')
+      for jj = 1:Na
+        if yunits ~= aos(jj).data.yunits
+          useYunitPlaceholder = true;
+          break;
+        end
+      end
+    end
+    ylabeli = '';
+    % Do we want to use a unit placeholder on the xaxis?
+    xunits = aos(1).data.xunits;
+    xunitPlaceholder = '[Mixed]';
+    useXunitPlaceholder = false;
+    if strcmpi(arrangement, 'stacked')
+      for jj = 1:Na
+        if xunits ~= aos(jj).data.xunits
+          useXunitPlaceholder = true;
+          break;
+        end
+      end
+    end
+    
+    % No plot
+    for jj = 1:Na
+      
+      if useYunitPlaceholder
+        yunits = yunitPlaceholder;
+      else
+        yunits = aos(jj).data.yunits;
+      end
+      if useXunitPlaceholder
+        xunits = xunitPlaceholder;
+      else
+        xunits = aos(jj).data.xunits;
+      end      
+      % set real and imag subplot handles to empty
+      fsax_r = [];
+      fsax_i = [];
+      % Get data
+      x = aos(jj).data.getX; y = aos(jj).data.getY;
+      % Do any math operations
+      ymath = parseOptions(jj, ymaths, 'y'); eval(sprintf('y = %s;', ymath));
+      xmath = parseOptions(jj, xmaths, 'x'); eval(sprintf('x = %s;', xmath));
+      % what figures do we need?
+      switch arrangement
+        case 'single'
+          fsfig = [fsfig figure];
+          col = colors{1};
+          % check if this data set is real or complex
+          if ~isreal(y)
+            % complex means we use two subplots
+            fsax_r = subplot(2,1,1); fsax_i = subplot(2,1,2);
+            fsax   = [fsax fsax_r fsax_i];
+            complexFig   = [complexFig get(fsax_r, 'Parent')];
+            complexAxes  = [complexAxes fsax_r fsax_i];
+          else
+            % real means we use a single subplot
+            fsax_r = subplot(1, 1, 1);
+            fsax = [fsax fsax_r];
+          end
+          % Make sure we reset the helper variables in this case
+          ymin = Inf; ymax = -Inf; xmin = Inf; xmax = -Inf;
+        case 'stacked'
+          if ~isempty(fig2plot), fsfig = fig2plot;
+          elseif jj == 1, fsfig = figure;
+          end
+          % if at least one of the input fsdata AOs is complex, we need to
+          % allow for subplots
+          if haveComplex
+            fsax_r = subplot(2,1,1,'Parent',fsfig); fsax_i = subplot(2,1,2,'Parent',fsfig);
+            fsax   = [fsax_r fsax_i];
+            if jj == 1
+              complexFig   = [complexFig fsfig];
+              complexAxes  = [complexAxes fsax_r fsax_i];
+            end
+          else
+            fsax_r = subplot(1, 1, 1,'Parent',fsfig);
+            fsax = fsax_r;
+          end
+          col = colors{mod(jj-1,length(colors))+1};
+          hold(fsax_r, 'on');
+          if ishandle(fsax_i)
+            hold(fsax_i, 'on');
+          end
+        case 'subplots'
+          if ~isempty(fig2plot), fsfig = fig2plot;
+          elseif jj == 1, fsfig = figure;
+          end
+          c = 1+(jj-1)*2;
+          sx = Na;
+          sy = 2;
+          % Now we have one or two subplots per input object.
+          if ~isreal(y)
+            fsax_r = subplot(sx, sy,c); fsax_i = subplot(sx, sy,c+1);
+            fsax   = [fsax fsax_r fsax_i];
+          else
+            fsax_r = subplot(sx, sy, c:c+1);
+            fsax   = [fsax fsax_r];
+          end
+          col = colors{1};
+          % Make sure we reset the helper variables in this case
+          ymin = Inf; ymax = -Inf; xmin = Inf; xmax = -Inf;
+        otherwise
+          error('### Unknown plot arrangement');
+      end
+      
+      % Process errors
+      [fcn, xu, xl, yu, yl] = process_errors(jj, size(y), type, XerrU, XerrL, YerrU, YerrL, aos(jj), autoErrors);
+      
+      %------- Plot the data
+      
+      % plot real or complex data and setup default values for scale and
+      % labels as we go.
+      if isreal(y)
+        % if the data are real, then we don't expect negative error bars
+        idx = find(yl>abs(y));
+        yl(idx) = 0.999*abs(y(idx));
+        switch fcn
+          case 'errorbar'
+            li = errorbar(fsax_r, x, y, yl, yu);
+            le = false;
+          case type
+            li   = feval(type, fsax_r, x, y);
+            le   = false; % we have no error plots
+          case 'errorbarxy'
+            lhs = errorbarxy(fsax_r, x, y, xu, yu, xl, yl);
+            li = lhs(1);
+            le = lhs(2);
+        end
+        fsli = [fsli li];
+        ylabelr = ''; ylabeli = 'imag';
+        yscaleR = 'log'; yscaleI = 'lin';
+        xscaleR = 'log'; xscaleI = 'log';
+      else
+        switch complexPlotType
+          case 'realimag'
+            switch fcn
+              case 'errorbar'
+                ry = real(y);
+                ferr = yl./abs(y);
+                yl = ry.*ferr;
+                yu = ry.*ferr;
+                li = errorbar(fsax_r, x, ry, yl, yu);
+                le = false;
+              case type
+                li   = feval(type, fsax_r, x, real(y));
+                le   = false; % we have no error plots
+              case 'errorbarxy'
+                lhs = errorbarxy(fsax_r, x, real(y), xu, yu, xl, yl);
+                li = lhs(1);
+                le = lhs(2);
+            end
+            switch fcn
+              case 'errorbar'
+                iy = imag(y);
+                ferr = yl./abs(y);
+                yl = iy.*ferr;
+                yu = iy.*ferr;
+                li = [li errorbar(fsax_i, x, iy, yl, yu)];
+                le = false;
+              case type
+                li   = [li feval(type, fsax_i, x, imag(y))];
+                le   = false; % we have no error plots
+              case 'errorbarxy'
+                lhs = errorbarxy(fsax_i, x, imag(y), xu, yu, xl, yl);
+                li = [li lhs(1)];
+                le = lhs(2);
+            end
+            fsli = [fsli li];
+            ylabelr = 'real'; ylabeli = 'imag';
+            yscaleR = 'lin'; yscaleI = 'lin';
+            xscaleR = 'log'; xscaleI = 'log';
+          case 'absdeg'
+            a = abs(y);
+            p = utils.math.phase(y);
+            % if the data are absolute values, then we don't expect
+            % negative error bars
+            idx = find(yl>abs(y));
+            yl(idx) = 0.999*abs(y(idx));
+            switch fcn
+              case 'errorbar'
+                li = errorbar(fsax_r, x, a, yl, yu);
+                le = false;
+              case type
+                li   = feval(type, fsax_r, x, abs(y));
+                le   = false; % we have no error plots
+              case 'errorbarxy'
+                lhs = errorbarxy(fsax_r, x, abs(y), xu, yu, xl, yl);
+                li = lhs(1); le = lhs(2);
+            end
+            switch fcn
+              case 'errorbar'
+                ferr = yl./a;
+                yl = 360.*ferr;
+                yu = 360.*ferr;
+                li = [li errorbar(fsax_i, x, p, yl, yu)];
+                le = false;
+              case type
+                li   = [li feval(type, fsax_i, x, utils.math.phase(y))];
+                le   = false; % we have no error plots
+              case 'errorbarxy'
+                lhs = errorbarxy(fsax_i, x, utils.math.phase(y), xu, yu, xl, yl);
+                li = [li lhs(1)]; le = lhs(2);
+            end
+            fsli = [fsli li];
+            ylabelr = 'Amplitude'; ylabeli = 'Phase';
+            yscaleR = 'log'; yscaleI = 'lin';
+            xscaleR = 'log'; xscaleI = 'log';
+          case 'absrad'
+            % if the data are absolute values, then we don't expect
+            % negative error bars
+            idx = find(yl>abs(y));
+            yl(idx) = 0.999*abs(y(idx));
+            switch fcn
+              case 'errorbar'
+                li = errorbar(fsax_r, x, abs(y), yl, yu);
+                le = false; %#ok<*NASGU>
+              case type
+                li   = feval(type, fsax_r, x, abs(y));
+                le   = false; % we have no error plots
+              case 'errorbarxy'
+                lhs = errorbarxy(fsax_r, x, abs(y), xu, yu, xl, yl);
+                li = lhs(1); le = lhs(2);
+            end
+            switch fcn
+              case 'errorbar'
+                ferr = yl./abs(y);
+                yl = pi.*ferr;
+                yu = pi.*ferr;
+                li = [li errorbar(fsax_i, x, angle(y), yl, yu)];
+                le = false;
+              case type
+                li   = [li feval(type, fsax_i, x, angle(y))];
+                le   = false; % we have no error plots
+              case 'errorbarxy'
+                lhs = errorbarxy(fsax_i, x, angle(y), xu, yu, xl, yl);
+                li = [li lhs(1)];
+                le = lhs(2);
+            end
+            fsli = [fsli li];
+            ylabelr = 'Amplitude'; ylabeli = 'Phase';
+            yscaleR = 'log'; yscaleI = 'lin';
+            xscaleR = 'log'; xscaleI = 'log';
+          otherwise
+            error('### Unknown plot type for complex data');
+        end
+      end
+      
+      %------- Axis properties
+      % axis counter
+      c = 1+(jj-1)*2;
+      
+      % Set real axis ylabel
+      ylstrR = parseOptions(c, ylabels, ylabelr);
+      ylstrR = prepareAxisLabel(yunits, ymath, ylstrR, 'y', UseLatex);
+      ylstrR = fixlabel(ylstrR);
+      if UseLatex
+        ylabel(fsax_r, ylstrR, 'interpreter', 'latex');
+      else
+        ylabel(fsax_r, ylstrR);
+      end
+      
+      % Set imag axis ylabel
+      if ishandle(fsax_i)
+        ylstrI = parseOptions(c+1, ylabels, ylabeli);
+        switch complexPlotType
+          case 'realimag'
+            ylstrI = prepareAxisLabel(yunits, ymath, ylstrI, 'y', UseLatex);
+          case 'absdeg'
+            ylstrI = prepareAxisLabel(unit('deg'), [], ylstrI, 'y', UseLatex);
+          case 'absrad'
+            ylstrI = prepareAxisLabel(unit('rad'), [], ylstrI, 'y', UseLatex);
+          otherwise
+        end
+        ylstrI = fixlabel(ylstrI);
+        if UseLatex
+          ylabel(fsax_i, ylstrI, 'interpreter', 'latex');
+        else
+          ylabel(fsax_i, ylstrI);
+        end
+      end
+      
+      % Set xlabel
+      xlstr = parseOptions(jj, xlabels, find(pl, 'XLabels'));
+      xlstr = prepareAxisLabel(xunits, xmath, xlstr, 'x', UseLatex);
+      xlstr = fixlabel(xlstr);
+      if isreal(y)
+        if UseLatex
+          xlabel(fsax_r, xlstr, 'interpreter', 'latex');
+        else
+          xlabel(fsax_r, xlstr);
+        end
+      else
+        % Do not draw Xlabel and XTicklabel on the real plot
+        set(fsax_r, 'XTickLabel',[]);
+      end
+      if ~isempty(fsax_i) && ishandle(fsax_i)
+        if UseLatex
+          xlabel(fsax_i, xlstr, 'interpreter', 'latex');
+        else
+          xlabel(fsax_i, xlstr);
+        end
+      end
+      
+      % Set grid on or off
+      grid(fsax_r, 'on');
+      if ~isempty(fsax_i) && ishandle(fsax_i), grid(fsax_i, 'on'); end
+      
+      % Set Y scale
+      yscaleR = parseOptions(c, yscales, yscaleR);
+      yscaleI = parseOptions(c+1, yscales, yscaleI);
+      set(fsax_r, 'YScale', yscaleR);
+      if ~isempty(fsax_i) && ishandle(fsax_i), set(fsax_i, 'YScale', yscaleI); end
+      
+      % Set X scale
+      xscaleR = parseOptions(c, xscales, xscaleR);
+      xscaleI = parseOptions(c+1, xscales, xscaleI);
+      set(fsax_r, 'XScale', xscaleR);
+      if ~isempty(fsax_i) && ishandle(fsax_i)
+        set(fsax_i, 'XScale', xscaleI);
+      end
+      
+      % Set Y range
+      yrange = parseOptions(c, yranges, []);
+      if ~isempty(yrange)
+        set(fsax_r, 'YLim', yrange);
+      elseif strcmpi(yscaleR, 'log')
+        [tcks,ymin,ymax] = getRealYDataTicks(y, ymin, ymax, complexPlotType, yscaleR);
+        nticks = numel(tcks);
+        if nticks>0 && nticks < 10
+          yrange = [tcks(1) tcks(end)];
+          set(fsax_r, 'YLim', yrange);
+          set(fsax_r, 'Ytickmode', 'manual');
+          set(fsax_r, 'Ytick', tcks);
+        else 
+          % go back to matlab autoscale
+          set(fsax_r, 'ylimmode', 'auto');
+          set(fsax_r, 'Ytick', []);
+          set(fsax_r, 'Ytickmode', 'auto');
+          
+        end
+      end
+      yrange = parseOptions(c+1, yranges, []);
+      if ~isempty(fsax_i) && ishandle(fsax_i)
+        if ~isempty(yrange)
+          set(fsax_i, 'YLim', yrange);
+        elseif strcmpi(yscaleI, 'log')
+          
+          % This doesn't really make sense since the imaginary part or
+          % phase or angle will always contain negative parts. Would the
+          % user really choose a log scale in that case?
+          %           tcks = getImagYDataTicks(y, ymin, ymax, complexPlotType, yscaleI);
+          %           if ~isempty(tcks)
+          %             yrange = [tcks(1) tcks(end)];
+          %             set(fsax_i, 'YLim', yrange);
+          %             set(fsax_i, 'Ytickmode', 'manual');
+          %             set(fsax_i, 'Ytick', tcks);
+          %           end
+        end
+      end
+      
+      % Set X range
+      xrange = parseOptions(c, xranges, []);
+      if ~isempty(xrange)
+        set(fsax_r, 'XLim', xrange);
+      elseif strcmpi(xscaleR, 'log')
+        xmin = min(xmin,  floor(log10(min(x(x>0)))));
+        xmax = max(xmax, ceil(log10(max(x(x>0)))));
+        tcks = logspace(xmin, xmax, xmax - xmin +1);
+        xrange = [tcks(1) tcks(end)];
+        set(fsax_r, 'XLim', xrange);
+        set(fsax_r, 'Xtickmode', 'manual');
+        set(fsax_r, 'Xtick', tcks);
+      end
+      xrange = parseOptions(c+1, xranges, []);
+      if ~isempty(fsax_i) && ishandle(fsax_i)
+        if ~isempty(xrange)
+          set(fsax_i, 'XLim', xrange);
+        elseif strcmpi(xscaleR, 'log')
+          xmin = min(xmin, floor(log10(min(x(x>0)))));
+          xmax = max(xmax, ceil(log10(max(x(x>0)))));
+          tcks = logspace(xmin, xmax, xmax - xmin +1);
+          xrange = [tcks(1) tcks(end)];
+          set(fsax_i, 'XLim', xrange);
+          set(fsax_i, 'Xtickmode', 'manual');
+          set(fsax_i, 'Xtick', tcks);
+        end
+      end
+      
+      %------- line properties
+      [col, lstyle, lwidth, mkr] = parseLineProps(jj, aos(jj).plotinfo, ...
+        linecolors, col, ...
+        linestyles, '-', ...
+        linewidths, get(0,'DefaultLineLineWidth'), ...
+        markers, 'None');
+      
+      % set props
+      set(li, 'Color', col);
+      set(li, 'LineStyle', lstyle);
+      set(li, 'LineWidth', lwidth);
+      if numel(x) == 1 && numel(y) == 1 && strcmp(mkr, 'None')
+        mkr = '.';
+      end
+      set(li, 'Marker', mkr);
+      
+      % Set legend string
+      if legendsOn
+        if ~isempty(aos(jj).plotinfo)            && ...
+            aos(jj).plotinfo.isparam('LEGEND_ON') && ...
+            ~aos(jj).plotinfo.find('LEGEND_ON')
+          for kk=1:numel(li)
+            set(get(get(li(kk),'Annotation'),'LegendInformation'),'IconDisplayStyle','off'); % Exclude line from legend
+          end
+        else
+          lstr = parseOptions(jj, legends, makeLegendStr(aos(jj)));
+          legendStrR = [legendStrR cellstr(lstr)];
+          if ~isreal(y)
+            legendStrI = [legendStrI cellstr(lstr)];
+          end
+          if strcmp(arrangement, 'single') || strcmp(arrangement, 'subplots')
+            legend(fsax_r, fixlabel(legendStrR{end}), 'Location', legendLoc);
+            if ~isempty(fsax_i) && ishandle(fsax_i)
+              h = legend(fsax_i, fixlabel(legendStrI), 'Location', legendLoc);
+            end
+          end
+        end
+      end
+      
+    end % End loop over AOs
+    
+    % Make sure the plots are refreshed
+    drawnow();
+    % Trim the size of complex plots
+    for jj = 1:length(complexFig)
+      p_r = get(complexAxes(2*jj-1), 'Position');
+      p_i = get(complexAxes(2*jj), 'Position');
+      dh = (p_r(2) - (p_i(2)+p_i(4)))/3;
+      set(complexAxes(2*jj-1), 'Position', [p_r(1) p_r(2)-dh p_r(3) p_r(4)+dh]);
+      set(complexAxes(2*jj), 'Position', [p_i(1) p_i(2) p_i(3) p_i(4)+dh]);
+    end
+    
+    % Process legends for stacked plots
+    if legendsOn
+      if strcmp(arrangement, 'stacked')
+        if ~isempty(legendStrR)
+          h = legend(fsax_r, fixlabel(legendStrR), 'Location', legendLoc);
+          set(h, 'FontSize', legendsFont);
+          if ~isempty(fsax_i) && ishandle(fsax_i)
+            h = legend(fsax_i, fixlabel(legendStrI), 'Location', legendLoc);
+            set(h, 'FontSize', legendsFont);
+          end
+        end
+      end
+    end
+  end % End ~isempty AOs
+  
+  % Apply plot settings to the figure
+  applyPlotSettings(fsax, fsli);
+  
+  % Set outputs
+  if nargout > 0
+    varargout{1} = fsfig;
+  end
+  if nargout > 1
+    varargout{2} = fsax;
+  end
+  if nargout == 3
+    varargout{3} = fsli;
+  end
+  if nargout > 3
+    error('### Too many output arguments');
+  end
+end % End fs_plot
+
+%--------------------------------------------------------------------------
+% Plot tsdata and xydata objects
+%
+function varargout = xy_plot(varargin)
+  
+  aos = varargin{1};
+  pl  = varargin{2};
+  fig2plot = varargin{3};
+  Na  = length(aos);
+  
+  UseLatex = find(pl, 'LatexLabels');
+  if ischar(UseLatex)
+    UseLatex = eval(UseLatex);
+  end
+  
+  % Extract parameters
+  arrangement = find(pl, 'Arrangement');
+  linecolors  = find(pl, 'LineColors');
+  colors      = find(pl, 'Colors');
+  linestyles  = find(pl, 'LineStyles');
+  markers     = find(pl, 'Markers');
+  linewidths  = find(pl, 'LineWidths');
+  legends     = find(pl, 'Legends');
+  legendsFont = find(pl, 'LegendFontSize');
+  ylabels     = find(pl, 'YLabels');
+  xlabels     = find(pl, 'XLabels');
+  xmaths      = find(pl, 'XMaths');
+  ymaths      = find(pl, 'YMaths');
+  yranges     = find(pl, 'YRanges');
+  xranges     = find(pl, 'XRanges');
+  yscales     = find(pl, 'YScales');
+  xscales     = find(pl, 'XScales');
+  type        = find(pl, 'Function');
+  legendLoc   = find(pl, 'LegendLocation');
+  xunits      = find(pl, 'Xunits');
+  autoErrors      = utils.prog.yes2true(find(pl, 'AUTOERRORS'));
+  
+  % Convert the colour if it is a character to a cell-string
+  if ischar(colors)
+    colors = cellstr(colors);
+  end
+  
+  % get errors
+  XerrL       = find(pl, 'XerrL');
+  XerrU       = find(pl, 'XerrU');
+  YerrL       = find(pl, 'YerrL');
+  YerrU       = find(pl, 'YerrU');
+  if ~iscell(XerrU), XerrU = {XerrU}; end
+  if ~iscell(XerrL), XerrL = {XerrL}; end
+  if ~iscell(YerrU), YerrU = {YerrU}; end
+  if ~iscell(YerrL), YerrL = {YerrL}; end
+  if (numel(XerrL) > 1 && numel(XerrL) ~= numel(aos)) || ...
+      (numel(YerrL) > 1 && numel(YerrL) ~= numel(aos)) || ...
+      (numel(XerrU) > 1 && numel(XerrU) ~= numel(aos)) || ...
+      (numel(YerrU) > 1 && numel(YerrU) ~= numel(aos))
+    error('### Please specify 1 set of errors for all AOs, or a set of errors for each AO.');
+  end
+  
+  torigin     = [];
+  
+  % check whether we want legends or not
+  if iscell(legends)
+    legendsOn = 1;
+  else
+    if strcmpi(legends, 'off')
+      legendsOn = 0;
+    else
+      legendsOn = 1;
+      legends = [];
+    end
+  end
+  
+  if ~isempty(ymaths) || ~isempty(xmaths)
+    warning('The use of the ''ymaths'' and ''xmaths'' parameters is deprecated. Please perform any calculations before calling iplot.');
+  end
+  
+  if ~iscell(linewidths), linewidths = {linewidths}; end
+  if ~iscell(linestyles), linestyles = {linestyles}; end
+  if ~iscell(linecolors), linecolors = {linecolors}; end
+  if ~iscell(markers), markers = {markers}; end
+  if ~iscell(legends), legends = {legends}; end
+  if ~iscell(ylabels), ylabels = {ylabels}; end
+  if ~iscell(xlabels), xlabels = {xlabels}; end
+  if ~iscell(xmaths), xmaths = {xmaths}; end
+  if ~iscell(ymaths), ymaths = {ymaths}; end
+  if ~iscell(xranges), xranges = {xranges}; end
+  if ~iscell(yranges), yranges = {yranges}; end
+  if ~iscell(xscales), xscales = {xscales}; end
+  if ~iscell(yscales), yscales = {yscales}; end
+  if ~iscell(xunits), xunits = {xunits}; end
+  
+  % collect figure handles
+  tsfig = []; tsax  = []; tsli  = [];
+  % Legend holder
+  legendStr = [];
+  if ~isempty(aos)
+    % Now loop over AOs to get earliest start time
+    T0 = 0;
+    if strcmp(arrangement, 'stacked')
+      T0 = 1e50;
+      for jj = 1:Na
+        % Get this AO
+        if isa(aos(jj).data, 'tsdata') && aos(jj).data.t0.utc_epoch_milli/1000 < T0
+          T0 = round(aos(jj).data.t0.utc_epoch_milli/1000);
+        end
+      end
+    end
+    
+    % Do we want to use a unit placeholder on the yaxis?
+    yunits = aos(1).data.yunits;
+    yunitPlaceholder = '[Mixed]';
+    useYunitPlaceholder = false;
+    if strcmpi(arrangement, 'stacked')
+      for jj = 1:Na
+        if yunits ~= aos(jj).data.yunits
+          useYunitPlaceholder = true;
+          break;
+        end
+      end
+    end
+    
+    % Do we want to use a unit placeholder on the xaxis?
+    firstXunits = aos(1).data.xunits;
+    xunitPlaceholder = '[Mixed]';
+    useXunitPlaceholder = false;
+    if strcmpi(arrangement, 'stacked')
+      for jj = 1:Na
+        if firstXunits ~= aos(jj).data.xunits
+          useXunitPlaceholder = true;
+          break;
+        end
+      end
+    end
+    
+    % Now loop over AOs
+    for jj = 1:Na
+      % Get this AO
+      t0off = 0;
+      
+      if useYunitPlaceholder
+        yunits = yunitPlaceholder;
+      else
+        yunits = aos(jj).data.yunits;
+      end
+      
+      % what figures do we need?
+      switch arrangement
+        case 'single'
+          tsfig = [tsfig figure];
+          tsax = subplot(1,1,1);
+          col = colors{1};
+          if isa(aos(jj).data, 'tsdata')
+            torigin = aos(jj).data.t0;
+          end
+        case 'stacked'
+          if ~isempty(fig2plot), tsfig = fig2plot;
+          elseif jj==1, tsfig = figure;
+          end
+          tsax = subplot(1,1,1,'Parent',tsfig);
+          col = colors{mod(jj-1,length(colors))+1};
+          hold on;
+          % deal with time-stamps here
+          if isa(aos(jj).data, 'tsdata')
+            t0off = aos(jj).data.t0.utc_epoch_milli/1000 - T0;
+          else
+            t0off = 0;
+          end
+          if isa(aos(jj).data, 'tsdata')
+            torigin = time(T0);
+          end
+        case 'subplots'
+          if ~isempty(fig2plot), tsfig = fig2plot;
+          elseif jj==1, tsfig = figure;
+          end
+          tsax = [tsax subplot(Na, 1, jj,'Parent',tsfig)];
+          col = colors{1};
+          if isa(aos(jj).data, 'tsdata')
+            torigin = aos(jj).data.t0;
+          end
+        otherwise
+          error('### Unknown plot arrangement');
+      end
+      
+      %------- Apply math functions
+      
+      % Get data and add t0 offset for this time-series
+      x = aos(jj).data.getX + t0off;
+      y = aos(jj).data.getY;
+      
+      % Apply any math operations
+      ymath = parseOptions(jj, ymaths, 'y'); eval(sprintf('y = %s;', ymath));
+      xmath = parseOptions(jj, xmaths, 'x'); eval(sprintf('x = %s;', xmath));
+      
+      % Process X units
+      if useXunitPlaceholder
+        xunit = xunitPlaceholder;
+        dateTicSpec = false;
+      else
+        if isa(aos(jj).data, 'tsdata')
+          xunitIn  = char(aos(jj).data.xunits);
+          xunit    = parseOptions(jj, xunits, xunitIn);
+          [x, xunit, dateTicSpec] = convertXunits(x, torigin, xunit, xunitIn);
+        elseif isa(aos(jj).data, 'xydata')
+          xunitIn  = char(aos(jj).data.xunits);
+          xunit    = parseOptions(jj, xunits, xunitIn);
+          dateTicSpec = false;
+        else
+          xunit = '';
+          dateTicSpec = false;
+        end
+      end
+
+      % Process errors
+      [fcn, xu, xl, yu, yl] = process_errors(jj, size(y), type, XerrU, XerrL, YerrU, YerrL, aos(jj), autoErrors);
+      
+      %------- Plot the data
+      
+      switch fcn
+        case 'errorbar'
+          li = errorbar(tsax(end), x, y, yl, yu);
+          le = false;
+        case type
+          li   = feval(type, tsax(end), x, y);
+          le   = false; % we have no error plots
+        case 'errorbarxy'
+          lhs = errorbarxy(tsax(end), x, y, xu, yu, xl, yl);
+          li = lhs(1);
+          le = lhs(2);
+      end
+      tsli = [tsli li];
+      if isa(aos(jj).data, 'tsdata')
+        title(sprintf('Time origin: %s', char(torigin)));
+      end
+      
+      %------- Add time origin to the axis handle
+      
+      if isempty(torigin)
+        torigin = time();
+      end
+      
+      set(tsax(end), 'UserData', torigin)
+      try
+        dcm_obj = datacursormode(get(tsfig(end),'Parent'));
+      catch
+        dcm_obj = datacursormode(tsfig(end));
+      end
+      set(dcm_obj, 'UpdateFcn', @utils.plottools.datacursormode)
+      
+      %---------- Call datetic
+      if dateTicSpec
+        datetick(tsax(end), 'x', xunit(2:end-1), 'keeplimits');
+      end
+      
+      %------- Axis properties
+      
+      % Set ylabel
+      ylstr = parseOptions(jj, ylabels, find(pl, 'YLabels'));
+      ylstr = prepareAxisLabel(yunits, ymath, ylstr, 'y', UseLatex);
+      ylstr = fixlabel(ylstr);
+      if UseLatex
+        ylabel(ylstr, 'interpreter', 'latex');
+      else
+        ylabel(ylstr);
+      end
+      
+      % Set xlabel
+      xlstr = parseOptions(jj, xlabels, find(pl, 'XLabels'));
+      xlstr = prepareAxisLabel(xunit, xmath, xlstr, 'x', UseLatex);
+      xlstr = fixlabel(xlstr);
+      if UseLatex
+        xlabel(xlstr, 'interpreter', 'latex');
+      else
+        xlabel(xlstr);
+      end
+      
+      % Set Y range
+      yrange = parseOptions(jj, yranges, []);
+      if ~isempty(yrange), set(tsax(end), 'YLim', yrange); end
+      
+      % Set X range
+      xrange = parseOptions(jj, xranges, []);
+      if ~isempty(xrange), set(tsax(end), 'XLim', xrange); end
+      
+      % Set Y scale
+      yscale = parseOptions(jj, yscales, 'lin');
+      set(tsax(end), 'YScale', yscale);
+      
+      % Set X scale
+      xscale = parseOptions(jj, xscales, 'lin');
+      set(tsax(end), 'XScale', xscale);
+      
+      % Set grid on or off
+      grid(tsax(end), 'on');
+      
+      
+      %------- line properties
+      [col, lstyle, lwidth, mkr] = parseLineProps(jj, aos(jj).plotinfo, ...
+        linecolors, col, ...
+        linestyles, '-', ...
+        linewidths, get(0,'DefaultLineLineWidth'), ...
+        markers, 'None');
+      
+      
+      % Set line color
+      set(li, 'Color', col);
+      if ~isempty(le) && ishandle(le), set(le, 'Color', col); end
+      % Set line style
+      set(li, 'LineStyle', lstyle);
+      if ishandle(le), set(le, 'LineStyle', lstyle); end
+      % Set markers
+      if numel(x) == 1 && numel(y) == 1 && strcmp(mkr, 'None')
+        mkr = '.';
+      end
+      set(li, 'Marker', mkr);
+      % Set line widths
+      set(li, 'LineWidth', lwidth);
+      if ~isempty(le) && ishandle(le), set(le, 'LineWidth', lwidth); end
+      
+      % Set legend string
+      if legendsOn
+        if ~isempty(aos(jj).plotinfo)            && ...
+            aos(jj).plotinfo.isparam('LEGEND_ON') && ...
+            ~aos(jj).plotinfo.find('LEGEND_ON')
+          for kk=1:numel(li)
+            set(get(get(li(kk),'Annotation'),'LegendInformation'),'IconDisplayStyle','off'); % Exclude line from legend
+          end
+        else
+          lstr = parseOptions(jj, legends, makeLegendStr(aos(jj)));
+          legendStr = [legendStr cellstr(lstr)];
+          % Set the legend now if we can
+          if strcmp(arrangement, 'single') || strcmp(arrangement, 'subplots')
+            legend(fixlabel(legendStr{end}), 'Location', legendLoc);
+          end
+        end
+      end
+    end
+    
+    % Process legends for stacked plots
+    if legendsOn
+      if strcmp(arrangement, 'stacked')
+        if ~isempty(legendStr)
+          h = legend(fixlabel(legendStr), 'Location', legendLoc);
+          set(h, 'FontSize', legendsFont);
+        end
+      end
+    end
+  end % End if empty AOs
+  
+  % Apply plot settings to the figure
+  applyPlotSettings(tsax, tsli);
+  
+  % Set outputs
+  if nargout > 0
+    varargout{1} = tsfig;
+  end
+  if nargout > 1
+    varargout{2} = tsax;
+  end
+  if nargout == 3
+    varargout{3} = tsli;
+  end
+  if nargout > 3
+    error('### Too many output arguments');
+  end
+end % end xy_plot
+
+
+%--------------------------------------------------------------------------
+% Plot cdata objects
+%
+function varargout = y_plot(varargin)
+  
+  aos = varargin{1};
+  pl  = varargin{2};
+  fig2plot = varargin{3};
+  
+  UseLatex = find(pl, 'LatexLabels');
+  if ischar(UseLatex)
+    UseLatex = eval(UseLatex);
+  end
+  
+  % Extract parameters
+  arrangement = find(pl, 'Arrangement');
+  linecolors  = find(pl, 'LineColors');
+  colors      = find(pl, 'Colors');
+  linestyles  = find(pl, 'LineStyles');
+  markers     = find(pl, 'Markers');
+  linewidths  = find(pl, 'LineWidths');
+  legends     = find(pl, 'Legends');
+  legendsFont = find(pl, 'LegendFontSize');
+  ylabels     = find(pl, 'YLabels');
+  xlabels     = find(pl, 'XLabels');
+  xmaths      = find(pl, 'XMaths');
+  ymaths      = find(pl, 'YMaths');
+  yranges     = find(pl, 'YRanges');
+  xranges     = find(pl, 'XRanges');
+  yscales     = find(pl, 'YScales');
+  xscales     = find(pl, 'XScales');
+  type        = find(pl, 'Function');
+  legendLoc   = find(pl, 'LegendLocation');
+  autoErrors      = find(pl, 'AUTOERRORS');
+  
+  % Convert the colour if it is a character to a cell-string
+  if ischar(colors)
+    colors = cellstr(colors);
+  end
+  
+  % get errors
+  YerrL       = find(pl, 'YerrL');
+  YerrU       = find(pl, 'YerrU');
+  if ~iscell(YerrU), YerrU = {YerrU}; end
+  if ~iscell(YerrL), YerrL = {YerrL}; end
+  if (numel(YerrL) > 1 && numel(YerrL) ~= numel(aos)) || ...
+      (numel(YerrU) > 1 && numel(YerrU) ~= numel(aos))
+    error('### Please specify 1 set of errors for all AOs, or a set of errors for each AO.');
+  end
+  
+  % check whether we want legends or not
+  if iscell(legends)
+    legendsOn = 1;
+  else
+    if strcmp(legends, 'off')
+      legendsOn = 0;
+    else
+      legendsOn = 1;
+      legends = [];
+    end
+  end
+  
+  if ~isempty(ymaths) || ~isempty(xmaths)
+    warning('The use of the ''ymaths'' and ''xmaths'' parameters is deprecated. Please perform any calculations before calling iplot.');
+  end
+  
+  if ~iscell(linewidths), linewidths = {linewidths}; end
+  if ~iscell(linestyles), linestyles = {linestyles}; end
+  if ~iscell(linecolors), linecolors = {linecolors}; end
+  if ~iscell(markers), markers = {markers}; end
+  if ~iscell(legends), legends = {legends}; end
+  if ~iscell(ylabels), ylabels = {ylabels}; end
+  if ~iscell(xlabels), xlabels = {xlabels}; end
+  if ~iscell(xmaths), xmaths = {xmaths}; end
+  if ~iscell(ymaths), ymaths = {ymaths}; end
+  if ~iscell(xranges), xranges = {xranges}; end
+  if ~iscell(yranges), yranges = {yranges}; end
+  if ~iscell(xscales), xscales = {xscales}; end
+  if ~iscell(yscales), yscales = {yscales}; end
+  
+  % collect figure handles
+  cfig = []; cax  = []; cli  = [];
+  % Legend holder
+  legendStr = [];
+  if ~isempty(aos)
+    
+    % Now loop over AOs
+    Na = length(aos);
+    
+    % Do we want to use a unit placeholder on the yaxis?
+    yunits = aos(1).data.yunits;
+    yunitPlaceholder = '[Mixed]';
+    useYunitPlaceholder = false;
+    if strcmpi(arrangement, 'stacked')
+      for jj = 1:Na
+        if yunits ~= aos(jj).data.yunits
+          useYunitPlaceholder = true;
+          break;
+        end
+      end
+    end
+    
+    for jj = 1:Na
+      if useYunitPlaceholder
+        yunits = yunitPlaceholder;
+      else
+        yunits = aos(jj).data.yunits;
+      end
+      
+      % what figures do we need?
+      switch arrangement
+        case 'single'
+          cfig = [cfig figure];
+          cax = subplot(1,1,1);
+          col = colors{1};
+        case 'stacked'
+          if ~isempty(fig2plot), cfig = fig2plot;
+          elseif jj==1, cfig = figure;
+          end
+          %           if jj==1, cfig = figure; end
+          cax = subplot(1,1,1,'Parent',cfig);
+          col = colors{mod(jj-1,length(colors))+1};
+          hold on;
+        case 'subplots'
+          if ~isempty(fig2plot), cfig = fig2plot;
+          elseif jj==1, cfig = figure;
+          end
+          %           if jj == 1, cfig = figure; end
+          cax = [cax subplot(Na, 1, jj)];
+          col = colors{1};
+        otherwise
+          error('### Unknown plot arrangement');
+      end
+      
+      % Get data
+      if isreal(aos(jj).data.getY)
+        x = 1:length(aos(jj).data.getY);
+        y = aos(jj).data.getY;
+      else
+        x = real(aos(jj).data.getY);
+        y = imag(aos(jj).data.getY);
+      end
+      
+      %------- Apply math functions
+      ymath = parseOptions(jj, ymaths, 'y'); eval(sprintf('y = %s;', ymath));
+      xmath = parseOptions(jj, xmaths, 'x'); eval(sprintf('x = %s;', xmath));
+      % Process errors
+      [fcn, xu, xl, yu, yl] = process_errors(jj, size(y), type, {[]}, {[]}, YerrU, YerrL, aos(jj), autoErrors);
+      
+      %------- Plot the data
+      switch fcn
+        case 'errorbar'
+          lhs = errorbarxy(cax(end), x, y,zeros(size(yl)),yu,zeros(size(yl)),yl);
+          idcs = lhs(1);
+          le = lhs(2);
+        case type
+          idcs   = feval(type, cax(end), x, y);
+          le   = false; % we have no error plots
+        case 'errorbarxy'
+          lhs = errorbarxy(cax(end), x, y, xu, yu, xl, yl);
+          idcs = lhs(1);
+          le = lhs(2);
+      end
+      %------- Plot the data
+      %       idcs = feval(type, cax(end), x, y);
+      %       cli = [cli idcs(1:end).'];
+      
+      %------- Axis properties
+      
+      % Set ylabel
+      ylstr = parseOptions(jj, ylabels, find(pl, 'YLabels'));
+      ylstr = prepareAxisLabel(yunits, ymath, ylstr, 'y', UseLatex);
+      ylstr = fixlabel(ylstr);
+      if UseLatex
+        ylabel(ylstr, 'interpreter', 'latex');
+      else
+        ylabel(ylstr);
+      end
+      
+      % Set xlabel
+      xlstr = parseOptions(jj, xlabels, find(pl, 'XLabels'));
+      xlstr = prepareAxisLabel(unit('Index'), xmath, xlstr, 'x', UseLatex);
+      xlstr = fixlabel(xlstr);
+      if UseLatex
+        xlabel(xlstr, 'interpreter', 'latex');
+      else
+        xlabel(xlstr);
+      end
+      
+      % Set Y scale
+      yscale = parseOptions(jj, yscales, 'lin');
+      set(cax(end), 'YScale', yscale);
+      
+      % Set X scale
+      xscale = parseOptions(jj, xscales, 'lin');
+      set(cax(end), 'XScale', xscale);
+      
+      % Set Y range
+      yrange = parseOptions(jj, yranges, []);
+      if ~isempty(yrange), set(cax(end), 'YLim', yrange); end
+      
+      % Set X range
+      xrange = parseOptions(jj, xranges, []);
+      if ~isempty(xrange), set(cax(end), 'XLim', xrange); end
+      
+      % Set grid on or off
+      grid(cax(end), 'on');
+      
+      %------- line properties
+      
+      [col, lstyle, lwidth, mkr] = parseLineProps(jj, aos(jj).plotinfo, ...
+        linecolors, col, ...
+        linestyles, '-', ...
+        linewidths, get(0,'DefaultLineLineWidth'), ...
+        markers, 'None');
+      
+      % Overide line colors with user defined colors
+      set(idcs, 'Color', col);
+      if ~isempty(le) && ishandle(le), set(le, 'Color', col); end
+      
+      % Set line style
+      set(idcs, 'LineStyle', lstyle);
+      if ishandle(le), set(le, 'LineStyle', lstyle); end
+      % Set Markers
+      if numel(x) == 1 && numel(y) == 1 && strcmp(mkr, 'None')
+        mkr = '.';
+      end
+      set(idcs, 'Marker', mkr);
+      % Set line widths
+      set(idcs, 'LineWidth', lwidth);
+      if ~isempty(le) && ishandle(le), set(le, 'LineWidth', lwidth); end
+      
+      % Set legend string
+      if legendsOn
+        if ~isempty(aos(jj).plotinfo)            && ...
+            aos(jj).plotinfo.isparam('LEGEND_ON') && ...
+            ~aos(jj).plotinfo.find('LEGEND_ON')
+          for kk=1:numel(li)
+            set(get(get(li(kk),'Annotation'),'LegendInformation'),'IconDisplayStyle','off'); % Exclude line from legend
+          end
+        else
+          lstr = parseOptions(jj, legends, makeLegendStr(aos(jj)));
+          legendStr = [legendStr cellstr(lstr)];
+          % Set the legend now if we can
+          if strcmp(arrangement, 'single') || strcmp(arrangement, 'subplots')
+            legend(fixlabel(legendStr{end}), 'Location', legendLoc);
+          end
+        end
+      end
+    end % End AO loop
+    
+    % Process legends for stacked plots
+    if legendsOn
+      if strcmp(arrangement, 'stacked')
+        if ~isempty(legendStr)
+          h = legend(fixlabel(legendStr), 'Location', legendLoc);
+          set(h, 'FontSize', legendsFont);
+        end
+      end
+    end
+    
+  end
+  
+  % Apply plot settings to the figure
+  applyPlotSettings(cax, cli);
+  
+  % Set outputs
+  if nargout > 0
+    varargout{1} = cfig;
+  end
+  if nargout > 1
+    varargout{2} = cax;
+  end
+  if nargout == 3
+    varargout{3} = cli;
+  end
+  if nargout > 3
+    error('### Too many output arguments');
+  end
+end % End y_plot
+
+%--------------------------------------------------------------------------
+% Plot xyzdata objects
+%
+function varargout = xyz_plot(varargin)
+  
+  aos = varargin{1};
+  pl  = varargin{2};
+  fig2plot = varargin{3};
+  
+  UseLatex = find(pl, 'LatexLabels');
+  if ischar(UseLatex)
+    UseLatex = eval(UseLatex);
+  end
+  
+  % Extract parameters
+  arrangement = find(pl, 'Arrangement');
+  legends     = find(pl, 'Legends');
+  legendsFont = find(pl, 'LegendFontSize');
+  zlabels     = find(pl, 'ZLabels');
+  ylabels     = find(pl, 'YLabels');
+  xlabels     = find(pl, 'XLabels');
+  xmaths      = find(pl, 'XMaths');
+  ymaths      = find(pl, 'YMaths');
+  zmaths      = find(pl, 'ZMaths');
+  legendLoc   = find(pl, 'LegendLocation');
+  yranges     = find(pl, 'YRanges');
+  xranges     = find(pl, 'XRanges');
+  zranges     = find(pl, 'ZRanges');
+  zscales     = find(pl, 'ZScales');
+  yscales     = find(pl, 'YScales');
+  xscales     = find(pl, 'XScales');
+  invertY     = find(pl, 'InvertY');
+  
+  % check whether we want legends or not
+  if iscell(legends)
+    legendsOn = 1;
+  else
+    if strcmp(legends, 'off')
+      legendsOn = 0;
+    else
+      legendsOn = 1;
+      legends = [];
+    end
+  end
+  
+  if ~isempty(ymaths) || ~isempty(xmaths)
+    warning('The use of the ''ymaths'' and ''xmaths'' parameters is deprecated. Please perform any calculations before calling iplot.');
+  end
+  
+  if ~iscell(legends), legends = {legends}; end
+  if ~iscell(ylabels), ylabels = {ylabels}; end
+  if ~iscell(xlabels), xlabels = {xlabels}; end
+  if ~iscell(zlabels), zlabels = {zlabels}; end
+  if ~iscell(xmaths), xmaths = {xmaths}; end
+  if ~iscell(ymaths), ymaths = {ymaths}; end
+  if ~iscell(zmaths), zmaths = {zmaths}; end
+  if ~iscell(xranges), xranges = {xranges}; end
+  if ~iscell(yranges), yranges = {yranges}; end
+  if ~iscell(zranges), zranges = {zranges}; end
+  if ~iscell(xscales), xscales = {xscales}; end
+  if ~iscell(yscales), yscales = {yscales}; end
+  if ~iscell(zscales), zscales = {zscales}; end
+  
+  
+  % collect figure handles
+  tdfig = [];
+  tdax  = [];
+  tdli  = [];
+  
+  % Legend holder
+  legendStr = [];
+  
+  if ~isempty(aos)
+    
+    % Now loop over AOs
+    Na = length(aos);
+    for jj = 1:Na
+      % what figures do we need?
+      switch arrangement
+        case 'single'
+          tdfig = [tdfig figure];
+          tdax = subplot(1,1,1);
+        case 'subplots'
+          if ~isempty(fig2plot), tdfig = fig2plot;
+          elseif jj==1, tdfig = figure;
+          end
+          %           if jj == 1, tdfig = figure; end
+          tdax = [tdax subplot(Na, 1, jj)];
+        otherwise
+          warning('!!! Plot arrangement ''%s'' not supported on XYZ plots. Using ''single'' instead.', arrangement);
+          arrangment = 'single';
+          tdfig = [tdfig figure];
+          tdax = subplot(1,1,1);
+      end
+      
+      %------- Apply math functions
+      x = aos(jj).data.x;
+      y = aos(jj).data.getY;
+      z = aos(jj).data.z;
+      
+      ymath = parseOptions(jj, ymaths, 'y'); eval(sprintf('y = %s;', ymath));
+      xmath = parseOptions(jj, xmaths, 'x'); eval(sprintf('x = %s;', xmath));
+      zmath = parseOptions(jj, zmaths, 'z'); eval(sprintf('z = %s;', zmath));
+      
+      %------- Plot the data
+      
+      idcs = pcolor(x,y,z);
+      tdli = [tdli idcs(1:end).'];
+      
+      % plot properties
+      set(idcs, 'EdgeColor', 'none');
+      
+      %------- Axis properties
+      
+      % Reverse y-direction for spectrograms
+      if invertY
+        set(tdax(end), 'YDir', 'reverse');
+      end
+      
+      % Set ylabel
+      ylstr = parseOptions(jj, ylabels, find(pl, 'YLabels'));
+      ylstr = prepareAxisLabel(aos(jj).data.yunits, ymath, ylstr, 'y', UseLatex);
+      ylstr = fixlabel(ylstr);
+      if UseLatex
+        ylabel(ylstr, 'interpreter', 'latex');
+      else
+        ylabel(ylstr);
+      end
+      
+      % Set xlabel
+      xlstr = parseOptions(jj, xlabels, find(pl, 'XLabels'));
+      xlstr = prepareAxisLabel(aos(jj).data.xunits, xmath, xlstr, 'x', UseLatex);
+      xlstr = fixlabel(xlstr);
+      if UseLatex
+        xlabel(xlstr, 'interpreter', 'latex');
+      else
+        xlabel(xlstr);
+      end
+      
+      % Set grid on or off
+      grid(tdax(end), 'on');
+      
+      % Set title string
+      if legendsOn
+        if ~isempty(aos(jj).plotinfo)            && ...
+            aos(jj).plotinfo.isparam('LEGEND_ON') && ...
+            ~aos(jj).plotinfo.find('LEGEND_ON')
+          for kk=1:numel(li)
+            set(get(get(li(kk),'Annotation'),'LegendInformation'),'IconDisplayStyle','off'); % Exclude line from legend
+          end
+        else
+          lstr = parseOptions(jj, legends, makeLegendStr(aos(jj)));
+          legendStr = [legendStr cellstr(lstr)];
+          % Set the legend now if we can
+          title(legendStr{end});
+        end
+      end
+      
+      % Set colorbars
+      hc = colorbar('peer', tdax(end));
+      zlstr = parseOptions(jj, zlabels, find(pl, 'Zlabels'));
+      zlstr = prepareAxisLabel(aos(jj).data.zunits, zmath, zlstr, 'z', UseLatex);
+      zlstr = fixlabel(zlstr);
+      ylh = get(hc, 'YLabel');
+      set(ylh, 'String', zlstr);
+      set(ylh, 'Fontsize', get(tdax(end), 'Fontsize'))
+      set(ylh, 'FontName', get(tdax(end), 'FontName'))
+      set(ylh, 'FontAngle', get(tdax(end), 'FontAngle'))
+      set(ylh, 'FontWeight', get(tdax(end), 'FontWeight'))
+      
+      
+      % Set Y scale
+      yscale = parseOptions(jj, yscales, 'lin');
+      set(tdax(end), 'YScale', yscale);
+      
+      % Set X scale
+      xscale = parseOptions(jj, xscales, 'lin');
+      set(tdax(end), 'XScale', xscale);
+      
+      % Set Z scale
+      zscale = parseOptions(jj, zscales, 'lin');
+      set(tdax(end), 'ZScale', zscale);
+      
+      % Set Y range
+      yrange = parseOptions(jj, yranges, []);
+      if ~isempty(yrange), set(tdax(end), 'YLim', yrange); end
+      
+      % Set X range
+      xrange = parseOptions(jj, xranges, []);
+      if ~isempty(xrange), set(tdax(end), 'XLim', xrange); end
+      
+      % Set Z range
+      zrange = parseOptions(jj, zranges, []);
+      if ~isempty(zrange), set(tdax(end), 'CLim', zrange); end
+    end
+  end
+  
+  % Apply plot settings to the figure
+  applyPlotSettings(tdax, tdli);
+  
+  % Set outputs
+  if nargout > 0
+    varargout{1} = tdfig;
+  end
+  if nargout > 1
+    varargout{2} = tdax;
+  end
+  if nargout == 3
+    varargout{3} = tdli;
+  end
+  if nargout > 3
+    error('### Too many output arguments');
+  end
+end % end xyz_plot
+
+%--------------------------------------------------------------------------
+% Get Info Object
+%--------------------------------------------------------------------------
+function ii = getInfo(varargin)
+  if nargin == 1 && strcmpi(varargin{1}, 'None')
+    sets = {};
+    pl   = [];
+  elseif nargin == 1&& ~isempty(varargin{1}) && ischar(varargin{1})
+    sets{1} = varargin{1};
+    pl = getDefaultPlist(sets{1});
+  else
+    sets = {'Time-series Plot', 'Frequency-series Plot', 'Y Data Plot', 'X-Y Data Plot', '3D Plot'};
+    % get plists
+    pl(size(sets)) = plist;
+    for k = 1:numel(sets)
+      pl(k) =  getDefaultPlist(sets{k});
+    end
+  end
+  % Build info object
+  ii = minfo(mfilename, 'ao', 'ltpda', utils.const.categories.output, '$Id: iplot.m,v 1.142 2011/08/15 06:08:28 hewitson Exp $', sets, pl);
+  ii.setModifier(false);
+  ii.setOutmin(0);
+end
+
+% Parse line properties from plist, or defaults
+function [col, lstyle, lwidth, mkr] = parseLineProps(jj, pli, ...
+    linecolors, dcol, ...
+    linestyles, dlstyle, ...
+    linewidths, dlwidth, ...
+    markers, dmkr)
+  
+  if isempty(pli)
+    pli = plist;
+  end
+  
+  % Set line color but overide with user colors
+  col = pli.find('color');
+  if isempty(col)
+    col = parseOptions(jj, linecolors, dcol);
+  end
+  
+  % Set line style
+  lstyle = pli.find('linestyle');
+  if isempty(lstyle)
+    lstyle = parseOptions(jj, linestyles, dlstyle);
+  end
+  
+  % Set line widths
+  lwidth = pli.find('linewidth');
+  if isempty(lwidth)
+    lwidth = parseOptions(jj, linewidths, dlwidth);
+  end
+  
+  % Set markers
+  mkr = pli.find('marker');
+  if isempty(mkr)
+    mkr = parseOptions(jj, markers, dmkr);
+  end
+  
+end
+
+
+%--------------------------------------------------------------------------
+% Get Default Plist
+%--------------------------------------------------------------------------
+function plout = getDefaultPlist(set)
+  persistent pl;
+  persistent lastset;
+  if exist('pl', 'var')==0 || isempty(pl) || ~strcmp(lastset, set)
+    pl = buildplist(set);
+    lastset = set;
+  end
+  pl.pset('LEGENDFONTSIZE', LTPDAprefs.legendFontSize);
+  plout = pl;
+end
+
+function out = buildplist(set)
+  
+  % Get the LTPDA color set for lines
+  colors = getappdata(0,'ltpda_default_plot_colors');
+  
+  out = plist();
+  
+  % Figure
+  p = param({'Figure',['The handle of the figure to plot in to. This will be ignored if the AOs to plot are inconsistent,<br>'...
+    'containing different class of data (such as tsdata and fsdata), or if the ''arrangement''<br>',...
+    'parameter is passed as ''single''.']}, paramValue.EMPTY_DOUBLE);
+  out.append(p);
+  
+  % Colors
+  p = param({'Colors', 'A list of colors which will be cycled through for each line in a plot.'}, colors);
+  out.append(p);
+  
+  % Arrangement
+  p = param({'Arrangement',['Select the plot layout:<ul>',...
+    '<li>''single''   - plot all AOs on individual figures</li>',...
+    '<li>''stacked''  - plot all AOs on the same axes</li>',...
+    '<li>''subplots'' - plot all AOs on subplots</li>'...
+    '</ul>']}, {1, {'stacked', 'single', 'subplots'}, paramValue.SINGLE});
+  out.append(p);
+  
+  % Function
+  p = param({'Function',['Specify the plot function:<ul>',...
+    '<li>''plot''</li>', ...
+    '<li>''stairs''</li>',...
+    '<li>''stem''</li>',...
+    '</ul>'...
+    '[*** doesn''t work for xyzdata AOs]']}, {1, {'plot', 'stairs', 'stem'}, paramValue.SINGLE});
+  out.append(p);
+  
+  % LineColors
+  p = param({'LineColors', ['A cell-array of color definitions, one for each trace.<br>'...
+    'Give an empty string to use the default color.']}, ...
+    {1, {''}, paramValue.OPTIONAL});
+  out.append(p);
+  
+  % LineColors
+  p = param({'LineStyles', ['A cell-array of line styles, one for each trace.<br>'...
+    'Give an empty string to use the default style.']}, ...
+    {1, {''}, paramValue.OPTIONAL});
+  out.append(p);
+  
+  % Markers
+  p = param({'Markers', ['A cell-array of markers, one for each trace.']}, ...
+    {1, {''}, paramValue.OPTIONAL});
+  out.append(p);
+  
+  % LineWidths
+  p = param({'LineWidths', ['A cell-array of line widths, one for each trace.<br>'...
+    'Give an empty string to use the default line width.']}, ...
+    {1, {''}, paramValue.OPTIONAL});
+  out.append(p);
+  
+  % Legends
+  p = param({'Legends', ['Give a cell-array of strings to be used for<br>'...
+    'the plot legends. If a cell contains an empty<br>'...
+    'string, the default legend string is built.<br>'...
+    'If a single string ''off'' is given instead of a<br>'...
+    'cell-array, then the legends are all switched off.']}, ...
+    {1, {''}, paramValue.OPTIONAL});
+  out.append(p);
+  
+  % LegendLocation
+  p = param({'LegendLocation','Choose the legend location.'}, ...
+    {5, {'North', 'South', 'East', 'West', ...
+    'NorthEast', 'NorthWest', 'SouthEast', 'SouthWest', ...
+    'NorthOutside', 'SouthOutside', 'EastOutside', 'WestOutside', ...
+    'NorthEastOutside', 'NorthWestOutside', 'SouthEastOutside', ...
+    'SouthWestOutside', 'Best', 'BestOutside'}, paramValue.SINGLE});
+  out.append(p);
+  
+  % LegendFontSize
+  p = param({'LegendFontSize','Choose the legend font size.'}, ...
+    {1, {LTPDAprefs.legendFontSize}, paramValue.SINGLE});
+  out.append(p);
+  
+  % XerrL
+  p = param({'XerrL','Lower bound error values for the X data points.'}, paramValue.EMPTY_DOUBLE);
+  out.append(p);
+  
+  % XerrU
+  p = param({'XerrU','Upper bound error values for the X data points.'}, paramValue.EMPTY_DOUBLE);
+  out.append(p);
+  
+  % YerrL
+  p = param({'YerrL','Lower bound error values for the Y data points.'}, paramValue.EMPTY_DOUBLE);
+  out.append(p);
+  
+  % YerrU
+  p = param({'YerrU','Upper bound error values for the Y data points.'}, paramValue.EMPTY_DOUBLE);
+  out.append(p);
+  
+  % XScales
+  p = param({'XScales', ['A cell-array specifying the scale to be used on each x-axis.<br>'...
+    'For example, {''lin'', ''log''}']}, {1, {''}, paramValue.OPTIONAL});
+  out.append(p);
+  
+  % YScales
+  p = param({'YScales', ['A cell-array specifying the scale to be used on each y-axis.<br>'...
+    'For example, {''lin'', ''log''}']}, {1, {''}, paramValue.OPTIONAL});
+  out.append(p);
+  
+  % XRanges
+  p = param({'XRanges', ['A cell-array specifying the ranges to be displayed on each x-axis.<br>'...
+    'For example, {[0 1], [-4 4]}.']}, {1, {''}, paramValue.OPTIONAL});
+  out.append(p);
+  
+  % YRanges
+  p = param({'YRanges', ['A cell-array specifying the ranges to be displayed on each y-axis.<br>'...
+    'For example, {[0 1], [-4 4]}.']}, {1, {''}, paramValue.OPTIONAL});
+  out.append(p);
+  
+  % LatexLabels
+  p = param({'LatexLabels','Use latex interpreter for axis labels.'}, paramValue.TRUE_FALSE);
+  p.val.setValIndex(2);
+  out.append(p);
+  
+  % YMaths
+  p = param({'YMaths',['Specify math operations to perform on the data vector ''y''. [DEPRECATED]<br>',...
+    'For example, <tt>plist(''Ymaths'', ''sqrt(y)'')</tt>.']}, paramValue.EMPTY_STRING);
+  out.append(p);
+  
+  
+  % No auto-errors
+  p = param({'AUTOERRORS',['If the AO contains errors, they will be plotted. You can avoid plotting the <br>',...
+    'errors by setting this to false.']}, paramValue.FALSE_TRUE);
+  out.append(p);
+  
+  switch lower(set)
+    case 'frequency-series plot'
+      % ComplexPlotType
+      p = param({'complexPlotType',['Specify how to plot complex data. Choose from:<ul>',...
+        '<li>''realimag''</li>',...
+        '<li>''absdeg''</li>',...
+        '<li>''absrad''</li>'...
+        '</ul>']}, {1, {'absdeg', 'realimag', 'absrad'}, paramValue.SINGLE});
+      out.append(p);
+      
+      % Xlabel
+      p = param({'XLabels',['Specify the labels to be used on the x-axes. The units are added from<br>',...
+        'the data object ''xunits'' property.']}, paramValue.STRING_VALUE('Frequency'));
+      out.append(p);
+      % ylabels
+      p = param({'YLabels',['Specify the labels to be used on the y-axes. The units are added from<br>',...
+        'the data object ''yunits'' property.']}, paramValue.STRING_VALUE(''));
+      out.append(p);
+      
+      % XMaths
+      p = param({'XMaths',['Specify math operations to perform on the data vector ''x''. [DEPRECATED]<br>',...
+        'For example, <tt>plist(''Xmaths'', ''abs(x)'')</tt>.']}, paramValue.EMPTY_STRING);
+      out.append(p);
+      
+    case 'time-series plot'
+      
+      % Xlabel
+      p = param({'XLabels',['Specify the labels to be used on the x-axes. The units are added from<br>',...
+        'the data object ''xunits'' property.']}, paramValue.STRING_VALUE('Time'));
+      out.append(p);
+      
+      % Ylabels
+      p = param({'YLabels',['Specify the labels to be used on the y-axes. The units are added from<br>',...
+        'the data object ''yunits'' property.']}, paramValue.STRING_VALUE('Amplitude'));
+      out.append(p);
+      
+      % Xunits
+      p = param({'Xunits', ['Specify the units of time on the x-axis as<ul>'...
+        '<li>''us''        - microseconds<li>' ...
+        '<li>''ms''        - milliseconds<li>' ...
+        '<li>''s''         - seconds<li>' ...
+        '<li>''m''         - minutes<li>' ...
+        '<li>''h''         - hours<li>' ...
+        '<li>''D''         - days<li>' ...
+        '<li>''M''         - months<li>' ...
+        '<li>''HH:MM:SS''  - using a date/time format</li>' ...
+        '</ul>']}, {3, {'us', 'ms', 's', 'm', 'h', 'D', 'M', 'HH:MM:SS', 'yyyy-mm-dd HH:MM:SS'}, paramValue.OPTIONAL});
+      out.append(p);
+      
+    case 'x-y data plot'
+      % Xlabel
+      p = param({'XLabels',['Specify the labels to be used on the x-axes. The units are added from<br>',...
+        'the data object ''xunits'' property.']}, paramValue.STRING_VALUE('X-data'));
+      out.append(p);
+      
+      % Ylabels
+      p = param({'YLabels',['Specify the labels to be used on the y-axes. The units are added from<br>',...
+        'the data object ''yunits'' property.']}, paramValue.STRING_VALUE('Y-data'));
+      out.append(p);
+      
+      % XMaths
+      p = param({'XMaths',['Specify math operations to perform on the data vector ''x''. [DEPRECATED]<br>',...
+        'For example, <tt>plist(''Xmaths'', ''abs(x)'')</tt>.']}, paramValue.EMPTY_STRING);
+      out.append(p);
+      
+    case '3d plot'
+      
+      out.pset('arrangement', 'single');
+      
+      % Xlabel
+      p = param({'XLabels',['Specify the labels to be used on the x-axes. The units are added from<br>',...
+        'the data object ''xunits'' property.']}, paramValue.STRING_VALUE('Time'));
+      out.append(p);
+      
+      % Ylabels
+      p = param({'YLabels',['Specify the labels to be used on the y-axes. The units are added from<br>',...
+        'the data object ''yunits'' property.']}, paramValue.STRING_VALUE('Frequency'));
+      out.append(p);
+      
+      % Zlabels
+      p = param({'ZLabels',['Specify the labels to be used on the z-axes. The units are added from<br>',...
+        'the data object ''zunits'' property.']}, paramValue.STRING_VALUE('Amplitude'));
+      out.append(p);
+      
+      % XMaths
+      p = param({'XMaths',['Specify math operations to perform on the data vector ''x''. [DEPRECATED]<br>',...
+        'For example, <tt>plist(''Xmaths'', ''abs(x)'')</tt>.']}, paramValue.EMPTY_STRING);
+      out.append(p);
+      
+      % ZMaths
+      p = param({'ZMaths',['Specify math operations to perform on the data vector ''z''. [DEPRECATED]<br>',...
+        'For example, <tt>plist(''Zmaths'', ''abs(z)'')</tt>.']}, paramValue.EMPTY_STRING);
+      out.append(p);
+      
+      % ZScales
+      p = param({'ZScales', ['A cell-array specifying the scale to be used on each z-axis.<br>'...
+        'For example, {''lin'', ''log''}']}, {1, {''}, paramValue.OPTIONAL});
+      out.append(p);
+      
+      % ZRanges
+      p = param({'ZRanges', ['A cell-array specifying the ranges to be displayed on each z-axis.<br>'...
+        'For example, {[0 1], [-4 4]}.']}, {1, {''}, paramValue.OPTIONAL});
+      out.append(p);
+      
+      % Invert y-axis
+      p = param({'InvertY', ['Invert the y-axis or not.']}, paramValue.TRUE_FALSE);
+      out.append(p);
+      
+      out.remove('linestyles');
+      out.remove('linewidths');
+      out.remove('linecolors');
+      out.remove('markers');
+      
+    case 'y data plot'
+      % Xlabel
+      p = param({'XLabels',['Specify the labels to be used on the x-axes. The units are added from<br>',...
+        'the data object ''xunits'' property.']}, paramValue.STRING_VALUE('Sample'));
+      out.append(p);
+      
+      % Ylabels
+      p = param({'YLabels',['Specify the labels to be used on the y-axes. The units are added from<br>',...
+        'the data object ''yunits'' property.']}, paramValue.STRING_VALUE('Value'));
+      out.append(p);
+    otherwise
+      error('### Unknown set [%s]', set);
+  end
+end
+
+
+function name = makeLegendStr(a)
+  
+  name = utils.plottools.label(a.name);
+  desc = utils.plottools.label(a.description);
+  
+  if isempty(name)
+    name = '?';
+  end
+  
+  if ~isempty(desc) && LTPDAprefs.includeDescription
+    name = [name ': ' desc];
+  end
+  
+  
+end
+
+% Perform some substitutions on the labels
+function ss = fixlabel(ss)
+  
+  MAX_LENGTH = 100;
+  wasCell = true;
+  if ~iscell(ss)
+    ss = {ss};
+    wasCell = false;
+  end
+  
+  for kk = 1:numel(ss)
+    s = ss{kk};
+    if ~isempty(s)
+      % Replace all ^(...) with ^{...}
+      jj = 1;
+      while jj < numel(s)
+        if strcmp(s(jj:jj+1), '^(')
+          % find next )
+          for k = 1:numel(s)-jj+1
+            if s(jj+k) == ')'
+              s(jj+1) = '{';
+              s(jj+k) = '}';
+              break;
+            end
+          end
+        end
+        jj = jj + 1;
+      end
+      % Replace all .^ with ^
+      s = strrep(s, '.^', '^');
+      
+      % reduce size
+      if length(s) > MAX_LENGTH
+        s = s(1:MAX_LENGTH-3);
+        if s(end) == '\'
+          s = s(1:end-1)
+        end
+        s = [ s '...' ];
+      end
+      
+    end
+    ss(kk) = {s};
+  end
+
+  if ~wasCell
+    ss = ss{1};
+  end
+  
+end
+
+%-----------------------------------------------
+% Change X data for time-series according to the specified xunits
+function [x, xunit, dateTicSpec] = convertXunits(x, t0, xunit, xunitIn)
+  
+  dateTicSpec = false;
+  
+  xunit = strtrim(xunit);
+  xunitIn = strtrim(xunitIn);
+  if ~strcmpi(strtrim(xunitIn), '[s]')
+    warning('### I can only convert from [s] to %s - ignoring requested Xunit', xunit);
+    xunit = xunitIn;
+  else
+    switch strtrim(xunit)
+      case {'[us]', 'us'}
+        x = x .* 1e6;
+      case {'[ms]', 'ms'}
+        x = x .* 1e3;
+      case {'[s]', 's'}
+      case {'[m]', 'm'}
+        x = x ./ 60;
+      case {'[h]', 'h'}
+        x = x ./ 3600;
+      case {'[D]', 'D'}
+        x = x ./ 86400;
+      otherwise
+        % then we have a datetic spec
+        dateTicSpec = true;
+        % first convert x data to serial date
+        st = format(t0, 'yyyy-mm-dd hh:mm:ss');
+        st = regexp(st, ' ', 'split');
+        st = [st{1} ' ' st{2}];
+        t0 = datenum(st); % get t0 as a serial date
+        x = t0 + x./86400; % convert x to days
+    end
+  end
+  if xunit(1) ~= '['
+    xunit = ['[' xunit];
+  end
+  if xunit(end) ~= ']'
+    xunit = [xunit ']'];
+  end
+  %                          'us'        - microseconds
+  %                          'ms'        - milliseconds
+  %                          's'         - seconds [default]
+  %                          'm'         - minutes
+  %                          'h'         - hours
+  %                          'D'         - days
+  %                          'M'         - months
+  %                          'HH:MM:SS'  - using a date/time format
+  
+end
+
+%----------------------------------------
+% Prepare an axis label
+function lstr = prepareAxisLabel(units, math, lstr, axis, UseLatex)
+  if isa(units, 'unit')
+    
+    if ismac && UseLatex
+      units = units.tolabel;
+    else
+      units = {fixlabel(char(units))};
+    end
+  else
+    units = {units};
+  end
+  if ~isempty(math)
+    if ~isempty(lstr)
+      lstr = strrep(math, axis, lstr);
+    end
+    lstr = [fixlabel(lstr) '  ' units{1} ];
+  else
+    lstr = [fixlabel(lstr) '  ' units{1}];
+  end
+end
+
+% Parse cell-array of options
+function opt = parseOptions(varargin) %jj, opts, dopt
+  
+  jj    = varargin{1};
+  opts = varargin{2};
+  dopt = varargin{3};
+  opt   = dopt;
+  
+  if ~iscell(opts)
+    opts = {opts};
+  end
+  Nopts = numel(opts);
+  
+  % First look for the 'all' keyword
+  if Nopts == 2 && strcmpi(opts{1}, 'all')
+    opt = opts{2};
+  else
+    if jj <= Nopts && ~isempty(opts{jj})
+      opt = opts{jj};
+    end
+  end
+  
+end
+
+
+
+% ERRORBARXY Customizable error bar plot in X and Y direction
+%
+% This function allows the user to plot the graph of x against y, along with
+% both x and y errorbars.
+%
+% With 4 numeric arguments (x,y,dx,dy), error bar are assumed to be of
+% same magnitude in both direction.
+%
+% One can specify lower and upper error bar with 6 numeric arguments
+% (x,y,dx_high,dy_high,dx_low,dy_low).
+%
+% x,y,dx,dy,... must be vectors of the same length
+%
+% [hp he] = errorbarxy(...) returns respectively the handle for the line
+% plot object and the line error bar object.
+%
+% It is possible to customize the line properties of the error bars by
+% adding pair of 'field/value' fields (such as 'LineWidth',2) that can be
+% understood by line. See LineProperties for more information.
+%
+% --------
+% EXAMPLES
+% --------
+% X = 10 * rand(7,1);
+% Y = 10 * rand(7,1);
+% dx = rand(7,1);
+% dy = rand(7,1);
+% errorbarxy(X,Y,dx,dy,'Color','k','LineStyle','none','Marker','o',...
+% 'MarkerFaceColor','w','LineWidth',1,'MarkerSize',11);
+%
+% X = 10 * rand(7,1);
+% Y = 10 * rand(7,1);
+% dx = rand(7,1);
+% dy = rand(7,1);
+% dx2 = rand(7,1);
+% dy2 = rand(7,1);
+% errorbarxy(X,Y,dx,dy,dx2,dy2,'Color','B','LineStyle','--','Marker','s',...
+% 'MarkerFaceColor','w','LineWidth',2,'MarkerSize',11);
+%
+% This is a rewrite of the m-file errorbarxy of James Rooney, to add
+% customizable line properties.
+
+% ------------------ INFO ------------------
+%   Authors: Jean-Yves Tinevez
+%   Work address: Max-Plank Insitute for Cell Biology and Genetics,
+%   Dresden,  Germany.
+%   Email: tinevez AT mpi-cbg DOT de
+%   November 2007 - June 2008;
+%   Permission is given to distribute and modify this file as long as this
+%   notice remains in it. Permission is also given to write to the author
+%   for any suggestion, comment, modification or usage.
+% ------------------ BEGIN CODE ------------------
+
+function out = errorbarxy(ax, x,y,varargin)
+  
+  
+  nargs = length(varargin);
+  
+  for i = 1 : nargs
+    
+    if ~( isnumeric(varargin{i}) )
+      break
+    end
+    errbaropt{i} = varargin{i};
+    
+  end
+  
+  
+  if i+3 < nargin
+    displayopt = varargin(i:end);
+    if isstruct(displayopt{1})
+      options = displayopt{1};
+    else
+      options = varargin2struct(displayopt);
+    end
+    erroroptions = options;
+  else
+    displayopt = [];
+  end
+  
+  options.Color = 'k';
+  erroroptions.LineStyle = '-';
+  erroroptions.Marker = 'none';
+  
+  
+  xw = (max(x)-min(x))/100;
+  yw = (max(y)-min(y))/100;
+  
+  n = length(varargin) - length(displayopt);
+  
+  if n == 2
+    % only 2 cells, so this is the same for lower and upper bar
+    ux = errbaropt{1};
+    lx = ux;
+    uy = errbaropt{2};
+    ly = uy;
+    
+  elseif n == 4
+    % 4 cells, the user specified both upper and lower limit
+    ux = errbaropt{1};
+    lx = errbaropt{3};
+    uy = errbaropt{2};
+    ly = errbaropt{4};
+    
+  else
+    errid = 'MATLAB:errorbarxy:BadArgumentNumber';
+    errmsg = ['Must have 4 or 6 numeric arguments, got ' ,num2str(n+2),'.'];
+    error(errid,errmsg);
+    
+  end
+  
+  
+  %%
+  
+  holdstate = ishold(gca);
+  X = [];
+  Y = [];
+  for t = 1:length(x)
+    
+    % x errorbars
+    X = [ X     nan x(t)-lx(t) x(t)+ux(t)    nan    x(t)-lx(t) x(t)-lx(t) nan     x(t)+ux(t) x(t)+ux(t)         ];
+    Y = [ Y     nan y(t) y(t)                nan    y(t)-yw y(t)+yw       nan     y(t)-yw y(t)+yw               ];
+    
+    % y errorbars
+    X = [ X     nan x(t) x(t)                nan    x(t)-xw x(t)+xw       nan     x(t)-xw x(t)+xw               ];
+    Y = [ Y     nan y(t)-ly(t) y(t)+uy(t)    nan    y(t)-ly(t) y(t)-ly(t) nan     y(t)+uy(t) y(t)+uy(t)         ];
+    
+  end
+  
+  hold on
+  axes(ax);
+  he = line(X,Y,erroroptions);
+  hp = plot(ax, x,y,options);
+  out = [hp he];
+  
+  % Return to initial hold state if needed
+  if ~holdstate
+    hold off
+  end
+  
+  function out = varargin2struct(in)
+    % I hould write help
+    
+    if ~iscell(in)
+      errid = 'MATLAB:struct2varargin:BadInputType';
+      errmsg = ['Input argument must be a cell, got a ' ,class(in),'.'];
+      error(errid,errmsg);
+    end
+    
+    n = length(in);
+    
+    if mod(n,2) ~= 0
+      errid = 'MATLAB:struct2varargin:BadInputType';
+      errmsg = ['Input argument must have an even number of elements, got ' ,num2str(n),'.'];
+      error(errid,errmsg);
+    end
+    
+    out = struct;
+    
+    for jj = 1 : n/2
+      name = in{2*jj-1};
+      value = in{2*jj};
+      out.(name) = value;
+    end
+    
+  end
+  
+end
+
+% Get a suitable ymin and ymax (in logscale) for the given
+% data.
+function [ticks,ymin,ymax] = getRealYDataTicks(y, ymin, ymax, complexPlotType, scale)
+  
+  ticks = [];
+  switch complexPlotType
+    case 'realimag'
+      if strcmpi(scale', 'log')
+        
+        % do nothing because it doesn't make sense since we will have
+        % negative values on a log scale
+        
+      end
+    case {'absdeg', 'absrad'}
+      
+      if strcmpi(scale, 'log')
+        % This is the main case we want to cover.
+        ay = abs(y);
+        newymin = min(ymin, floor(log10(min(ay(ay>0)))));
+        newymax = max(ymax, ceil(log10(max(ay(ay>0)))));
+        
+        if ~isempty(newymin) && ~isempty(newymax)
+          ymin = newymin;
+          ymax = newymax;
+        
+          if ymin == ymax
+            ymin = floor(log10(min(ay)/10));
+            ymax = ceil(log10(max(ay)*10));
+          end
+        
+        else
+          
+          if ymin == inf
+            ymin = -1;
+          end
+          
+          if ymax == -inf
+            ymax = 1;
+          end
+                  
+        end
+        nticks = ymax - ymin +1;
+        % can we reduce this if they don't all fit?
+        
+        ticks = logspace(ymin, ymax, nticks);
+      end
+      
+    otherwise
+      error('### Unknown plot type for complex data');
+  end
+  
+end
+
+% Get a suitable ymin and ymax (in linscale) for the given
+% data.
+function ticks = getImagYDataTicks(y, ymin, ymax, complexPlotType, scale)
+  
+  
+  ticks = [];
+  switch complexPlotType
+    case 'realimag'
+      if strcmpi(scale', 'log')
+        
+        % do nothing because it doesn't make sense since we will have
+        % negative values on a log scale
+        
+      end
+    case 'absdeg'
+      
+      if strcmpi(scale', 'log')
+        % do nothing because it doesn't make sense since we will have
+        % negative values on a log scale
+      end
+      
+    case 'absrad'
+      
+    otherwise
+      error('### Unknown plot type for complex data');
+  end
+  
+  
+end
+
+
+%-------------------
+% Process errorbars
+function [fcn, xu, xl, yu, yl] = process_errors(jj, dsize, ptype, XerrU, XerrL, YerrU, YerrL, a, auto)
+  
+  if numel(XerrL) == 1
+    xl = XerrL{1};
+  else
+    xl = XerrL{jj};
+  end
+  if numel(XerrU) == 1
+    xu = XerrU{1};
+  else
+    xu = XerrU{jj};
+  end
+  if numel(YerrL) == 1
+    yl = YerrL{1};
+  else
+    yl = YerrL{jj};
+  end
+  if numel(YerrU) == 1
+    yu = YerrU{1};
+  else
+    yu = YerrU{jj};
+  end
+  
+  % Check if we have AOs
+  if isa(xl, 'ao'), xl = xl.data.getY; end
+  if isa(xu, 'ao'), xu = xu.data.getY; end
+  if isa(yl, 'ao'), yl = yl.data.getY; end
+  if isa(yu, 'ao'), yu = yu.data.getY; end
+  
+  if isempty(xl) && ~isempty(xu)
+    xl = xu;
+  end
+  if isempty(xu) && ~isempty(xl)
+    xu = xl;
+  end
+  if isempty(yl) && ~isempty(yu)
+    yl = yu;
+  end
+  if isempty(yu) && ~isempty(yl)
+    yu = yl;
+  end
+  
+  
+  
+  % If the AO has errors, we use them
+  if ~isempty(a.dy) && auto
+    yl = a.dy;
+    yu = a.dy;
+    yu(yu==inf) = 0;
+    yl(yl==inf) = 0;
+  end
+  
+  if isempty(xl) && isempty(xu) && isempty(yu) && isempty(yl)
+    fcn = ptype;
+  elseif isempty(xl) && isempty(xu)
+    fcn = 'errorbar';
+  else
+    fcn = 'errorbarxy';
+  end
+  
+  if isempty(xl), xl = zeros(dsize); end
+  if isempty(yl), yl = zeros(dsize); end
+  if isempty(xu), xu = zeros(dsize); end
+  if isempty(yu), yu = zeros(dsize); end
+  if numel(xl) == 1, xl = xl.*ones(dsize); end
+  if numel(xu) == 1, xu = xu.*ones(dsize); end
+  if numel(yu) == 1, yu = yu.*ones(dsize); end
+  if numel(yl) == 1, yl = yl.*ones(dsize); end
+end
+
+function applyPlotSettings(axesH, lineH)
+  
+  prefs = getappdata(0, 'LTPDApreferences');
+  jPlotPrefs = prefs.getPlotPrefs();
+  
+  if jPlotPrefs.getPlotApplyPlotSettings.equals(mpipeline.ltpdapreferences.EnumPlotSetting.IPLOT_ONLY)
+    
+    % Set all axes properteis
+    for ii =1:numel(axesH)
+      set(axesH(ii), 'FontSize', double(jPlotPrefs.getPlotDefaultAxesFontSize));
+      set(axesH(ii), 'LineWidth', double(jPlotPrefs.getPlotDefaultAxesLineWidth));
+      set(axesH(ii), 'GridLineStyle', char(jPlotPrefs.getPlotDefaultAxesGridLineStyle));
+      set(axesH(ii), 'MinorGridLineStyle', char(jPlotPrefs.getPlotDefaultAxesMinorGridLineStyle));
+      switch char(jPlotPrefs.getPlotDefaultAxesFontWeight)
+        case 'Plain'
+          set(axesH(ii), 'FontWeight', 'normal');
+        case 'Bold'
+          set(axesH(ii), 'FontWeight', 'bold');
+        case 'Italic'
+          set(axesH(ii), 'FontWeight', 'light');
+        case 'Bold Italic'
+          set(axesH(ii), 'FontWeight', 'demi');
+        otherwise
+          error('### Unknown value (%s) for the default axes property ''FontWeight''', char(jPlotPrefs.getPlotDefaultAxesFontWeight));
+      end
+    end
+    
+    % Set all line properties
+    for ii = 1:numel(lineH) 
+      set(lineH(ii), 'LineWidth', double(jPlotPrefs.getPlotDefaultLineLineWidth));
+      set(lineH(ii), 'MarkerSize', double(jPlotPrefs.getPlotDefaultLineMarkerSize));
+    end
+  end
+end